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.线程的状态

  • 新建状态(New)

    刚刚创建的并且未调用start方法的线程
  • 可运行状态(Runnable)

    只有新建状态下的线程才能调用start方法,然后线程由新建状态进入可运行状态
  • 锁阻塞状态(Blocked)

    当前线程运行到需要锁对象时,当前锁对象已经被其他线程持有,那么当前线程进入锁阻塞状态!
  • 限时等待状态(Timed_waiting)

    当前线程执行到Thread.sleep(毫秒)时,当前线程进入限时等待状态!
  • 无限等待状态(Waiting)

    线程如何进入Waiting(无线等待状态)
    
        1.该线程首先要持有锁对象
        2.调用锁对象的wait方法
        3.该线程会自动释放锁对象,然后进入无限等待状态 
    
    其他线程如何唤醒Waiting状态的线程
    
        1.其他线程首先也要持有锁对象
        2.调用锁对象的notify方法 
        3.被唤醒的线程进入锁阻塞状态,直到其他线程释放锁对象,被唤醒线程再次抢到对象才能进入可运行状态     
  • 消亡状态(Terminated)

    当前线程的任务执行完毕,线程默认进入总结状态

4.等待唤醒机制Wait和Notify

生产者与消费者问题(代码演示)
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();
                            }
                        }
                    }
                }
            }
        });
    }
}

猜你喜欢

转载自www.cnblogs.com/xiaozhang666/p/13183198.html