一,不同方式创建多个线程并打印
(1)定义了一个RunA实现Runnable接口,定义list存储数据,并重写了run方法 ,在run方法里定义循环向list中添加数据a;在main方法中创建a,b两个线程并引用该run方法,输出run对象的list和长度
public static void mainB(String[] args) {
RunA run=new RunA();
Thread a=new Thread(run);
Thread b=new Thread(run);
a.start();
b.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(run.list);
System.out.println(run.list.size());
}
}
class RunA implements Runnable{
public List list=new ArrayList();
@Override
public void run() {
for(int i=0;i<10;i++){
list.add("a");
}
}
}
(2) 创建一个ThreadA类继承Thread(线程)定义一个list来存储数据,重写run方法,在main方法中创建ThreadA的对象线程a,b,并启动线程
class ThreadA extends Thread{
public List list=new ArrayList();
@Override
public void run() {
for(int i=0;i<10;i++){
list.add("a");
}
}
}
//2.
public static void mainB(String[] args) {
RunA run=new RunA();
Thread a=new Thread(run);
Thread b=new Thread(run);
a.start();
b.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(run.list);
System.out.println(run.list.size());
}
}
二,锁对象 Lock
注意:用Lock需要加锁解锁
创建锁对象
Lock lock=new ReentrantLock();//创建锁对象//Lock lock=new ReentrantLock(true);//加true 设置为公平锁
加锁 成功返回true 失败返回false
lock.lock();
解锁
lock.unlock();
创建method方法,在主方法中调用,创建a,b线程并运行
package com.easy725;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class EasyThreadB {
//锁对象 Lock
//用lock需要加锁解锁
Lock lock=new ReentrantLock();//创建锁对象
//Lock lock=new ReentrantLock(true);//加true 设置为公平锁
//锁默认非公平锁
public void method(){
// lock.lock();//加锁
//lock.tryLock()//尝试加锁 加锁成功true 失败返回false
if(lock.tryLock()){//尝试加锁
System.out.println(Thread.currentThread().getName()+"进入方法");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束方法");
lock.unlock();//解锁
}else{
System.out.println("未成功加锁======去执行其它代码");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
method();
}
}
public static void main(String[] args) {
Runnable run=new EasyThreadB()::method;//当调用runnable里面的run方法时,相当于调用method方法·
Thread a=new Thread(run);
Thread b=new Thread(run);
a.start();
b.start();
}
}
在运行过程中一次只能给加一个锁,下一个使用需要等待该锁解锁才能使用。进程0加锁成功先进入方法,执行进程;同时进程1请求加锁, 进入等待状态;直到进程0结束,同时还没有解锁,所以还会发生一次未成功加锁,然后发生解锁,进程1加锁成功进入方法
三,读锁和写锁
进程进入方法后,写锁可以多个同时访问,读锁只能一个访问结束后才能开始下一个,读锁和写锁不能同时访问,只能写锁或读锁结束才能开始读锁或写锁。
main线程的任务是启动这些线程
cpu分配资源时是随机的,main线程在启动完别的线程以后它的结束也是随机的
所有锁都默认为非公平锁,只有ReentranLock可以设置为公平锁
package com.easy725;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class EasyThreadC {
public static ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
public static ReentrantLock rl=new ReentrantLock();
public static void method(){
System.out.println(Thread.currentThread().getName()+"进入方法");
Lock lock= rrwl.readLock();//读锁
lock.lock();
System.out.println(Thread.currentThread().getName()+"加锁成功---读锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"方法结束");
lock.unlock();
}
public static void methodWrite(){
System.out.println(Thread.currentThread().getName()+"进入方法");
Lock lock= rrwl.writeLock();//写锁
lock.lock();
System.out.println(Thread.currentThread().getName()+"加锁成功---写锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"方法结束");
lock.unlock();
}
public static void main(String[] args) {
Runnable run=EasyThreadC::method;
Runnable runWrite=EasyThreadC::methodWrite;
Thread a=new Thread(run);
a.start();
Thread b=new Thread(run);
b.start();
Thread c=new Thread(run);
c.start();
Thread d=new Thread(run);
d.start();
Thread e=new Thread(run);
e.start();
Thread f=new Thread(runWrite);
f.start();
Thread g=new Thread(runWrite);
g.start();
Thread h=new Thread(runWrite);
h.start();
Thread i=new Thread(runWrite);
i.start();
System.out.println("main线程结束----");
}
}
四,wait 和 notify (等待和唤醒)
wait()方法可以使线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)
OBJ.wait();//让执行到该行代码的线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)
锁对象:synchronized关键字或显示锁ReentrantLock
例:
synchronized (OBJ){}//这里OBJ就是锁对象
notify()唤醒一条被该锁对象wait的线程 非公平锁
notifyAll();唤醒全部被锁对象wait的线程
synchronized (OBJ){ OBJ.notify();//唤醒一条被该锁对象wait的线程 非公平锁 OBJ.notifyAll();//唤醒全部被锁对象wait的线程
wait和sleep的区别
(1)wait使Object中定义的方法 ,可以有锁对象,让执行到改行代码的线程进入到等待状态
sleep使Thread类中定义的静态方法,可以让执行到改行的线程进入等待状态
(2)区别:1.sleep需要传入一个毫秒,到达时间会自动唤醒
wait不能自动唤醒,必须要调用notify或notifyAll方法唤醒
2.sleep方法保持锁状态进入等待状态
wait方法会解除锁状态,其他线程可以进入运行
package com.easy725;
public class EasyThreadD {
public static final Object OBJ=new Object();//常量全部大写
public static void method(){
System.out.println(Thread.currentThread().getName()+"进入方法");
synchronized (OBJ){
OBJ.notify();//唤醒一条被该锁对象wait的线程 非公平锁
// OBJ.notifyAll();//唤醒全部被锁对象wait的线程
System.out.println(Thread.currentThread().getName()+"进入同步代码块");
try {
try {
System.out.println(Thread.currentThread().getName()+"进入等待状态");
OBJ.wait();//让执行到该行代码的线程进入等待状态(在等待池等待)(只有锁对象才能调用wait方法)
System.out.println(Thread.currentThread().getName()+"重新运行");
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束同步代码块");
OBJ.notify();//必须在同步代码块中才能唤醒
}
}
public static void main(String[] args) {
Runnable run=EasyThreadD::method;
Thread a=new Thread(run);
a.start();
Thread b=new Thread(run);
b.start();
Thread c=new Thread(run);
c.start();
Thread d=new Thread(run);
d.start();
}
}
五,线程池 池==重用
功能:完成线程的创建和管理,销毁线程
(1)使用ThreadPoolExecutor创建一个线程池tpe
BlockingQueue qu=new ArrayBlockingQueue(12); ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,10,10, TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
(2)线程任务 Runnable Callable
Runnable通过execute方法提交到线程池执行
Callable通过submit犯法提交到线程池执行,并返回一个futur对象,用来获取任务结果,使用Future.get()方法获取结果,这样可以阻塞主线程直到仍无执行完成
创建一个工作队列qu用来存放待执行的任务,( 创建Runnable任务run并提交到线程池执行)创建callable任务call到线程池执行,并获取future对象
注意:线程池对象需要关闭,使用shutdouwn()销毁线程
package com.easy725;
import java.util.Queue;
import java.util.concurrent.*;
public class EasyExecuters {
//线程池 池==重用
//完成线程创建和管理,销毁线程
public static void main(String[] args) throws ExecutionException, InterruptedException {
BlockingQueue qu=new ArrayBlockingQueue(12);
ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,10,10,
TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
//线程任务 Runnable Callable
Runnable run=EasyExecuters::method;
tpe.execute(run);
Callable<String> call=EasyExecuters::methodCall;
Future<String> f=tpe.submit(call);
// tpe.submit(run);
System.out.println(f.get());//会等待线程执行完毕
//线程池对象需要关闭
tpe.shutdown();//销毁线程,关闭
}
public static void method(){
System.out.println(Thread.currentThread().getName()+"执行代码");
}
public static String methodCall() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"执行代码call");
Thread.sleep(2000);
return "callResult";
}
}
六 线程池
1,线程池的七个参数
BlockingQueue queue=new ArrayBlockingQueue(12); ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor( 5,8,10, TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() );//(核心线程数,最大线程数,空闲线程存活时间,空闲线程存活时间单位,工作队列,线程工厂,拒绝策略)
2.四中回绝策略
AbortPolicy 放弃该任务并会抛出一个异常.RejectedExecutionException
CallerRunsPolicy 调用者执行,让传递任务的线程执行此任务
DiscardOldestPolicy 放弃队列中时间最长的任务,不会抛出异常
DiscardPolicy 直接放弃新的任务,不会抛出异常
3.线程池的工作原理
任务放置在工作队列中
1)池中是否有空闲的线程,如果有让该线程执行任务
2)如果池中有空闲的 线程,判断池中的线程数量没有达到核心线程数
3)如果没有达到核心线程数,创建新的线程执行任务,直到填满核心线程数,如果已经达到, 优先在队列中存储线程,直到队列填满
4)工作队列填满后再添加新的任务,判断是否达到最大线程数,如果没有就创建新的线程执行任务 ,直到创建到最大线程数
5)已经填满最大线程数,队列也已经填满,没有空闲的线程吗,就执行回绝策略 ;线程池中的线程达到(超过)核心线程数,超出的数量会根据存活时间进行销毁,直到数量达到核心线程数 。如果线程的数量少于核心线程数,不会消亡
4.java中内置的线程池对象
1)Executors.newCachedThreadPool();可以根据工作任务来创建线程,如果没有空闲的线程就创建新的线程,线程存活时间使60s
2)Executors.newFixedThreadPool(10);设定最大线程数量
3)Executors.newScheduledThreadPool(10);提供定时运行的处理方案
4)Executors.newSingleThreadExecutor();创建一个具有单个线程的线程池,保障任务队列完全按照顺序执行
理论上可以无线创建线程数
ExecutorService threadPoolExecutor=Executors.newCachedThreadPool();
package com.easy725;
import java.util.concurrent.*;
public class EasyExcutersA {
public static void main(String[] args) {
BlockingQueue queue=new ArrayBlockingQueue(12);
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
5,8,10,
TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()
);
// ExecutorService threadPoolExecutor=Executors.newCachedThreadPool();//理论上线程数是无限创建的
Runnable run=()->{
System.out.println(Thread.currentThread().getName()+"执行代码");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行完毕");
};
for(int i=0;i<17;i++){
threadPoolExecutor.execute(run);
}
threadPoolExecutor.shutdown();
}
}
执行线程为17个,核心线程数刚好满五个
标签:Java,Thread,笔记,run,线程,new,println,day10,public From: https://blog.csdn.net/qq_63095129/article/details/140688521