多线程 ExecutorService CountDownLatch使用

 

一 Java通过Executors提供四种线程池,分别为: 
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

二、 ExecutorService 的submit() 与execute()区别 
1、 submit()可以接收runnable无返回值和callable有返回值 
      execute()接收runnable 无返回值

2、submit有返回值,而execute没有  


三、关闭线程池方法 shotdown() showdownNow()区别 

 

当我们使用shutdownNow方法关闭线程池时,一定要对任务里进行异常捕获。

当我们使用shuwdown方法关闭线程池时,一定要确保任务里不会有永久阻塞等待的逻辑,否则线程池就关闭不了。

最后,一定要记得,shutdownNow和shuwdown调用完,线程池并不是立马就关闭了,要想等待线程池关闭,还需调用awaitTermination方法来阻塞等待。


shutdown() 关闭了提交通道,用submit()是无效(停止接收新任务)原来的任务继续执行
shutdownNow() 停止接收新任务,原来的任务停止执行


CountDownLatch是JDK提供给我们的多线程间通信的一个工具,用于让主线程知道任务完成的进度。
如果需要等待所有的线程在执行完后触发一个操作,这个时候你就需要用到CountDownLatch。

//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };   
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//将count值减1
public void countDown() { };  

 

public void doSome(int num){
     // 创建一个线程池,线程数2
     ExecutorService pool = Executors.newFixedThreadPool(2);
     // CountDownLatch用来监控子线程
     CountDownLatch endSigle = new CountDownLatch(2);
     Callable xxxCall = new Xxaaa(a);
     Callable xxxCall1 = new Xxaaa1(a);
     Future ocrSearchFuture = pool.submit(xxxCall);//1
     Future ocrSearchFuture = pool.submit(xxxCall1);//2
     Xxaaa xxaaa =ocrSearchFuture.get()
     try{
         // 等待两个线程执行结束     
         endSigle.await();
         new Thread(new UserCall(paramMap,.......).start();
     }
     catch (Exception e){
         LOGGER.info(e);
         return null;
     }
     finally{
         if (null != pool && !pool.isShutdown()){
             pool.shutdown();
         }
     }
 }
 public class Xxaaa implements Callable{
     private String a;
     public OcrSearchCall(a){
         this.a = a;
     }
     @SuppressWarnings("finally")
     public xxaaa call(){
         //将count值减1,
         endSigle.countDown();

         Xxaaa xxaaa = null;
         return xxaaa;
     }

     public class UserCall implements Runnable{
         //基本参数
         private Map paramMap;
         public UserCall(Map paramMap,......){
             this.paramMap = paramMap;
......
         }

         @SuppressWarnings("finally")
         public void run(){
             int a=1;
         }
     }

实例:

/* 线程池可以把线程复用起来,减少线程创建销毁的时间和资源消耗,提高了程序任务执行的吞吐率。
    就像线程属于全局使用的资源一样,线程池一般也是全局性,对整个应用进程的线程复用做有效的管理。设计者一般都会把线程池作为类的静态成员或者单例成员,存活于整个进程的生命周期。*/

   /* 如果没有设置核心线程数,比如 newCachedThreadPool ,在线程池的线程空闲时间到达 60s 后,线程会关闭,所有线程关闭后线程池也相应关闭回收。
    如果设置了核心线程数,比如 newSingleThreadExecutor 和 newFixedThreadPool ,如果没有主动去关闭,或者设置核心线程的超时时间,核心线程会一直存在不会被关闭,这个线程池就不会被释放回收。
   */
   //newFixedThreadPool线程数设置50,不会被回收
     private   ExecutorService pool = Executors.newFixedThreadPool(2);
 @RequestMapping("/testUserInfoCall")
    @ResponseBody
    public String testUserInfoCall(){
        String result="";
        try{
            long startTime=System.currentTimeMillis();
            for (int i = 0; i < 3; i++) {

                result+= getAreaPress();

            }
            long endTime=System.currentTimeMillis()-startTime;
            System.out.println("整个方法耗时:"+endTime+"ms");
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return result;
    }

    public String getAreaPress(){
        String result="打印-----=";
        try{
                long startTime=System.currentTimeMillis();
                /* 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
               第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
               第三:提高线程的可管理性。*/
                CountDownLatch flag = new CountDownLatch(2);
                Callable userInfoCall = new UserInfoCall();
                Future userInfoFuture = pool.submit(userInfoCall);
                int activeCount = ((ThreadPoolExecutor)pool).getActiveCount();
                long taskCount= ((ThreadPoolExecutor) pool).getTaskCount();
                long completedTaskCount= ((ThreadPoolExecutor) pool).getCompletedTaskCount();
                int  getPoolSize=((ThreadPoolExecutor) pool).getPoolSize();
                int getLargestPoolSize=((ThreadPoolExecutor) pool).getLargestPoolSize();

                System.out.println("活跃线程数:"+activeCount);
                System.out.println("线程池已经执行的和未执行的任务总数:"+taskCount);
                System.out.println("线程池当前的线程数量:"+getPoolSize);
                System.out.println("线程池已完成的任务数量,该值小于等于taskCount:"+completedTaskCount);
                System.out.println("线程池曾经创建过的最大线程数量。通过这个数据可以知道线程池是否满过,也就是达到了maximumPoolSize:"+getLargestPoolSize);
                //向线程池中提交任务的submit方法不是阻塞方法,而Future.get方法是一个阻塞方法,
                // 当submit提交多个任务时,只有所有任务都完成后,才能使用get按照任务的提交顺序得到返回结果,
                // 所以一般需要使用future.isDone先判断任务是否全部执行完成,完成后再使用future.get得到结果
                // 。(也可以用get (long timeout, TimeUnit unit)方法可以设置超时时间,防止无限时间的等待)
                // Integer a = userInfoFuture.get(6000, TimeUnit.MILLISECONDS);
                //userInfoFuture.get()等待线程返回结果才能继续向下执行-》如果不使用则直接不等线程执行继续往下
                //userInfoFuture.get();
                long endTime=System.currentTimeMillis()-startTime;
                System.out.println("耗时:"+endTime+"ms");

        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return result;
    }

 

注意此处:Future模式是多线程设计常用的一种设计模式。Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。

Future userInfoFuture = pool.submit(userInfoCall);
userInfoFuture.get()

多线程 ExecutorService CountDownLatch使用_第1张图片

 

final CountDownLatch endSign = new CountDownLatch(3);

endSign .await() 当为0时候才可以继续执行下去

  public static void main(String[] args) {
        try{
            List> list=null;
            long startTime=System.currentTimeMillis();
            list= getAreaPress111();
            for (int i = 0; i < list.size(); i++) {
                Integer flag= list.get(i).get();
                System.out.println("====="+i+"========"+flag);
            }
            long endTime=System.currentTimeMillis()-startTime;
            System.out.println("整个方法耗时:"+endTime+"ms");
        }catch (Exception e){
            System.out.println("异常:"+e);
        }
    }

    private static   List> getAreaPress111(){
        List> futures = new ArrayList>();
        ExecutorService pool = Executors.newFixedThreadPool(3);
        final CountDownLatch endSign = new CountDownLatch(3);
        try {
            for (int i = 0; i < 3; i++) {
                Callable userInfoCall = new UserInfoCall(endSign);
                Future future = pool.submit(userInfoCall);
             /*   Future future = pool.submit(new Callable() {
                    @Override
                    public Integer call() throws Exception {
                        Thread.sleep(5000);
                        endSign.countDown();
                        System.out.println("sss"+endSign.getCount());
                        return 1;
                    }
                });*/
                futures.add(future);
            }
            //等待三个线程执行结束 才能继续向下执行
            endSign.await();
            pool.shutdown();
        } catch (InterruptedException e) {
            System.out.println(e);
        }
        return futures;
    }

 

你可能感兴趣的:(java)