Executor框架,死锁,线程状态,等待唤醒机制
https://blog.csdn.net/tongdanping/article/details/79604637
1.什么是Executor框架
线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象
的操作,无需反复创建线程而消耗过多资源。
合理利用线程池能够带来三个好处:
1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
线程池的使用
Executor框架包括3大部分:
(1)任务。也就是工作单元,包括被执行任务需要实现的接口:Runnable接口或者Callable接口;
(2)任务的执行。也就是把任务分派给多个线程的执行机制,包括Executor接口及继承自Executor接口的ExecutorService接口。
(3)异步计算的结果。包括Future接口及实现了Future接口的FutureTask类。
线程池的顶层接口: java.util.concurrent.Executor 线程池的子接口: java.util.concurrent.ExecutorService 线程池的工具类: java.util.concurrent.Executors 其中有一个静态方法,用于创建线程池的实现类对象: public static ExecutorService newFixedThreadPool(int nThreads);创建一个具有指定线程数量的线程池对象 ExecutorService线程池接口中定义了一个提交任务的方法: public Future<?> submit(Runnable r);向当前的线程池中提交某个"无返回值"任务 public Future<T> submit(Callable<T> r);向当前的线程池中提交某个"有返回值"任务
体系:
大体使用流程:
代码示例:
有返回值和无返回值两种
public class TreadPoolTest { static ExecutorService executorService = Executors.newFixedThreadPool(3); public static void main(String[] args) throws ExecutionException, InterruptedException { //无返回值任务 // for (int i = 0; i < 10; i++) { // executorService.submit(new Runnable() { // @Override // public void run() { // System.out.println(Thread.currentThread().getName() + "开始了"); // try { // Thread.sleep(2000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() + "结束了。。。"); // } // }); // } //有返回值 Future<Integer> future = executorService.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int num = 0; for (int i = 0; i < 10; i++) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } num++; } return num; } }); System.out.println("结束了submit"); System.out.println("阻塞了submit"); System.out.println(future.get()); } }
需要注意:
1.Future类需要确定泛型。
2.future.get() 会阻塞程序,等待已提交的任务返回完成。
3.Executors.newFixedThreadPool(3);默认调用的底层
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
- corePoolSize: 线程池核心线程数
- maximumPoolSize:线程池最大数
- keepAliveTime: 空闲线程存活时间
- unit: 时间单位
- workQueue: 线程池所使用的缓冲队列
Executor框架成员:ThreadPoolExecutor实现类、ScheduledThreadPoolExecutor实现类、Future接口、Runnable和Callable接口、Executors工厂类
2.死锁
什么是死锁
两个线程,两个锁对象
线程A获取锁对象1,线程B获取锁对象2,
线程A还需要锁对象2,才能执行
线程B还需要锁对象1,才能执行
线程A和B就相互等待对象释放锁对象,这种情况称为死锁!
a.至少有两个线程
b.至少有两个锁对象
c.需要反向嵌套获取锁对象
public class DeadLock { public static void main(String[] args) { Object o = new Object(); Object o2 = new Object(); new Thread(){ @Override public void run() { synchronized (o){ System.out.println("线程锁ooooo"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o2){ System.out.println("线程锁o2"); } } } }.start(); new Thread(){ @Override public void run() { synchronized (o2){ System.out.println("线程锁o2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o){ System.out.println("线程锁ooooo"); } } } }.start(); } }
3.线程的状态
-
刚刚创建的并且未调用start方法的线程
-
可运行状态(Runnable)
只有新建状态下的线程才能调用start方法,然后线程由新建状态进入可运行状态
-
锁阻塞状态(Blocked)
当前线程运行到需要锁对象时,当前锁对象已经被其他线程持有,那么当前线程进入锁阻塞状态!
-
限时等待状态(Timed_waiting)
当前线程执行到Thread.sleep(毫秒)时,当前线程进入限时等待状态!
-
无限等待状态(Waiting)
线程如何进入Waiting(无线等待状态) 1.该线程首先要持有锁对象 2.调用锁对象的wait方法 3.该线程会自动释放锁对象,然后进入无限等待状态 其他线程如何唤醒Waiting状态的线程 1.其他线程首先也要持有锁对象 2.调用锁对象的notify方法 3.被唤醒的线程进入锁阻塞状态,直到其他线程释放锁对象,被唤醒线程再次抢到对象才能进入可运行状态
-
消亡状态(Terminated)
当前线程的任务执行完毕,线程默认进入总结状态
4.等待唤醒机制
public class TestDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); Object objects = new Object(); //线程池 ExecutorService executorService = Executors.newFixedThreadPool(2); //1生产者 executorService.submit(new Runnable() { @Override public void run() { synchronized (list) { while (true) { if (list.size() == 0) { list.add("狗不理"); System.out.println("添加了狗不理"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } list.notify(); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }); //2购买者 executorService.submit(new Runnable() { @Override public void run() { synchronized (list) { while (true) { if (list.size() > 0) { list.remove(0); System.out.println("吃饱了"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } list.notify(); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }); } }