zoukankan      html  css  js  c++  java
  • 并发工具类和线程池

    1.并发工具类
      1.CountDownLatch:可以实现线程计数,阻塞后续线程
        CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
        countDown()实现计数器-1
        await()等待拦截方法,等待计数器为0时再放行,否则则一直阻塞
        getCount()获取当前计数器中计数数量

    案例:

    /**
     * 等待子线程全部执行完毕之后再执行主线程内容
     * @param args
     */
    private static CountDownLatch countDownLatch=new CountDownLatch(2);
    public static void main(String[] args) throws InterruptedException {
    	System.out.println("======主线程开始运行=====");
    	//第一个子线程
    	new Thread(()->{
    		System.out.println("子线程"+Thread.currentThread().getName()+"开始运行~");
    		//线程数量-1操作,通知该线程运行完毕
    		countDownLatch.countDown();
    	}).start();
    
    	//第二个子线程
    	new Thread(()->{
    		System.out.println("子线程"+Thread.currentThread().getName()+"开始运行~");
    		//线程数量-1操作,通知该线程运行完毕
    		countDownLatch.countDown();
    	}).start();
    
    	//等待,等待计数器中线程计数为0时才继续向下执行
    	countDownLatch.await();
    	System.out.println("子线程执行完毕,主线程继续执行");
    
    
    
    	//获取当前计数线程数量
    	/*while (true){
    		if(countDownLatch.getCount()==0){
    			System.out.println("子线程执行完毕,主线程继续执行");
    			break;
    		}
    	}*/
    }
    

      


        2.CyclicBarrier:类似于栅栏,进行拦截,等待所有线程都准备,然后统一放行,阻塞当前线程

    //设置等待线程数量,当线程数量到达指定数量时,统一向下运行
    private static CyclicBarrier cyclicBarrier=new CyclicBarrier(10);
    public static void main(String[] args) {
    	//创建10个线程
    	for (int i = 1; i <=10 ; i++) {
    		new Thread(()->{
    			try {
    				Thread.sleep(100);
    				System.out.println(Thread.currentThread().getName()+"准备就绪");
    				//等待
    				cyclicBarrier.await();
    			} catch (InterruptedException | BrokenBarrierException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName()+"开始比赛~");
    		}).start();
    	}
    }
    

      


        3.Semaphore:可以做资源控制,容器中有几个资源,那么线程执行时先申请资源,资源如果可用则继续执行,如果资源不可用则阻塞等待
    当资源占用完毕之后将该资源释放,其他线程排队占用

    private static Semaphore semaphore=new Semaphore(3);
    public static void main(String[] args) {
    	for (int i = 1; i <=10 ; i++) {
    		new Thread(()->{
    			try {
    				//申请资源,发生阻塞
    				System.out.println(Thread.currentThread().getName()+"申请茅坑~");
    				semaphore.acquire();
    				System.out.println(Thread.currentThread().getName()+"可以安心上厕所了");
    				//模拟上厕所时间
    				Thread.sleep(1000);
    				System.out.println(Thread.currentThread().getName()+"舒服,上完了~");
    				//释放资源
    				semaphore.release();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}).start();
    	}
    }


        4.Exchanger:可以执行线程的资源交换,线程数量必须为偶数,因为是两两相互交换资源,如果不是偶数默认情况下导致阻塞,可以设置交换资源超时时间

    public class ExchangerDemo {
    	private static String str1="资源1";
    	private static String str2="资源2";
    	//构建资源交换对象
    	private static Exchanger<String> stringExchanger=new Exchanger<>();
    	public static void main(String[] args) {
    		//第一个线程
    		new Thread(()->{
    			System.out.println(Thread.currentThread().getName()+"初始占用资源:"+str1);
    			//资源交换,将资源交给其他线程和获取到其他线程交换过来的资源
    			try {
    				String newStr = stringExchanger.exchange(str1);
    				System.out.println(Thread.currentThread().getName()+"交换资源:"+newStr);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}).start();
    
    		//第二个线程
    		new Thread(()->{
    			System.out.println(Thread.currentThread().getName()+"初始占用资源:"+str2);
    			//资源交换,将资源交给其他线程和获取到其他线程交换过来的资源
    			try {
    				String newStr = stringExchanger.exchange(str2);
    				System.out.println(Thread.currentThread().getName()+"交换资源:"+newStr);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}).start();
    
    		//第三个线程
    		new Thread(()->{
    			System.out.println(Thread.currentThread().getName()+"初始占用资源:"+str2);
    			//资源交换,将资源交给其他线程和获取到其他线程交换过来的资源
    			try {
    				//设置资源交换超时时间
    				String newStr = stringExchanger.exchange(str2,1000, TimeUnit.MILLISECONDS);
    				System.out.println(Thread.currentThread().getName()+"交换资源:"+newStr);
    			} catch (InterruptedException | TimeoutException e) {
    				e.printStackTrace();
    			}
    		}).start();
    	}
    }
    

      

      2.线程池
        类似于一个池子,可以存放/管理线程

        1.使用线程池的好处
          第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
          第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
          第三:提高线程的可管理性

        2.如何使用线程池
          2.1线程池分类
          线程池顶级类ThreadPoolExecutor最终实现Executor接口,在JUC包下,通过Executors类可以创建不同类型的线程池,分类如下
            1.newScheduledThreadPool 定时任务线程池,可以设置任务时间
            2.newFixedThreadPool 定长线程池
            3.newSingleThreadExecutor 利用的是单线程,单线程处理任务,一般不用
            4.newCachedThreadPool 带缓存的线程池
          2.2 构建线程池
            1.newCachedThreadPool线程池,可缓存,可以重复利用

    //构建一个线程池,可以重复利用线程
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 1; i <=10 ; i++) {
    	//创建线程池
    	executorService.execute(()->{
    		System.out.println("创建线程池"+Thread.currentThread().getName());
    	});
    }


            2.newFixedThreadPool创建一个固定线程数量的线程池

    //构建线程池对象
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
    	//创建线程
    	executorService.execute(()->{
    		System.out.println("创建线程:"+Thread.currentThread().getName());
    	});
    }
    

            3.newScheduledThreadPool

    //创建一个线程池
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
    for (int i = 0; i < 10; i++) {
    	scheduledExecutorService.schedule(()->{
    		System.out.println("创建线程:"+Thread.currentThread().getName());
    	},1000, TimeUnit.MILLISECONDS);
    }


            4.newSingleThreadExecutor单线程池

    //创建一个线程池
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
    	executorService.execute(()->{
    		System.out.println("创建线程:"+Thread.currentThread().getName());
    	});
    }
    

      

          3.所有的线程池分类底层调用的都是ThreadPoolExecutor()构造方法,该构造方法中每一个参数含义
          public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue)

            1.corePoolSize代表核心线程池大小,当有任务时,会创建对应线程处理对应任务,当线程到达一定数量后,则会缓存到队列当中,不会再次创建新的线程
            2.maximumPoolSize: 线程池最大线程数,它表示在线程池中最多能创建多少个线程
            3.keepAliveTime: 表示线程没有任务执行时最多保持多久时间会终止。
            4.unit: 参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性

          4.如何确定线程池中创建线程数量
            考虑CPU密集和IO密集,如果不考虑IO情况下,一般是处理器数量+1,如果考虑IO,则处理器*2

  • 相关阅读:
    Maven安装与环境配置(Windows)
    Java配置----JDK开发环境搭建及环境变量配置
    js中的join(),reverse()与 split()函数用法解析
    Vue2.0 搭建Vue脚手架(vue-cli)
    vue: WebStorm设置快速编译运行
    优秀博客推荐
    Springboot读取自定义配置文件节点
    vue——报错:Cannot read property '__ob__' of undefined
    css——内容溢出显示垂直滚动条,内容不超出就不显示滚动条
    js——实现多选
  • 原文地址:https://www.cnblogs.com/F017/p/12525261.html
Copyright © 2011-2022 走看看