zoukankan      html  css  js  c++  java
  • 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();
                                }
                            }
                        }
                    }
                }
            });
        }
    }
  • 相关阅读:
    04_Javascript初步第二天(上)
    用python实现省市县多级嵌套下拉列表
    爬虫之 BeautifulSoup与Xpath
    爬虫之 selenium模块
    爬虫请求库 requests
    抽屉网自动点赞 评论
    爬取京东商品信息
    爬取豆瓣电影top250
    爬虫基本原理
    Django auth认证
  • 原文地址:https://www.cnblogs.com/xiaozhang666/p/13183198.html
Copyright © 2011-2022 走看看