JUC就是java.util.concurrent包,这个包俗称JUC,外面都是解决并发问题的一些货色。该包的地位位于java上面的rt.jar包上面
4大罕用并发工具类:
CountDownLatchCountDownLatch是我目前应用比拟多的类,CountDownLatch初始化时会给定一个计数,而后每次调用countDown() 计数减1,
当计数未达到0之前调用await() 办法会阻塞直到计数减到0;
应用场景:多用于划分工作由多个线程执行,例如:最近写个豆瓣爬虫,须要爬取每个电影的前五页短评,能够划分成五个线程来解决数据。通过latch.await()保障全副实现再返回。
public void latch() throws InterruptedException { int count= 5; CountDownLatch latch = new CountDownLatch(count); for (int x=0;x<count;x++){ new Worker(x*20,latch).start(); } latch.await(); System.out.println("全副执行结束"); } class Worker extends Thread{ Integer start; CountDownLatch latch; public Worker(Integer start,CountDownLatch latch){ this.start=start; this.latch=latch; } @Override public void run() { System.out.println(start+" 已执行"); latch.countDown(); } }输入如下:
20 已执行0 已执行40 已执行60 已执行80 已执行全副执行结束CyclicBarrier它容许一组线程相互期待,直到达到某个公共屏障点 (common barrier point)也就是阻塞在调用cyclicBarrier.await()的中央。
看上去CyclicBarrier 跟CountDownLatch 性能上相似,java培训在官网doc上CountDownLatch的形容上就阐明了,CountDownLatch 的计数无奈被重置,如果须要重置计数,请思考应用CyclicBarrier。
CyclicBarrier初始时还可增加一个Runnable的参数, 此Runnable在CyclicBarrier的数目达到后,所有其它线程被唤醒前被最初一个进入 CyclicBarrier 的线程执行
应用场景:相似CyclicBarrier,然而 CyclicBarrier提供了几个countdownlatch 没有的办法以应酬更简单的场景,例如:
getNumberWaiting() 获取阻塞线程数量,
isBroken() 用来晓得阻塞的线程是否被中断等办法。
reset() 将屏障重置为其初始状态。如果所有参与者目前都在屏障处期待,则它们将返回,同时抛出一个 BrokenBarrierException。
public void latch() throws InterruptedException { int count = 5; CyclicBarrier cb = new CyclicBarrier(count, new Runnable() { @Override public void run() { System.out.println("全副执行结束"); } }); ExecutorService executorService = Executors.newFixedThreadPool(count); while (true){ for (int x=0;x<count;x++){ executorService.execute(new Worker(x,cb)); } } } class Worker extends Thread { Integer start; CyclicBarrier cyclicBarrier; public Worker(Integer start, CyclicBarrier cyclicBarrier) { this.start = start; this.cyclicBarrier = cyclicBarrier; } @Override public void run() { System.out.println(start + " 已执行"); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }输入如下:
0 已执行3 已执行4 已执行2 已执行1 已执行全副执行结束0 已执行1 已执行2 已执行3 已执行4 已执行全副执行结束SemaphoreSemaphore 信号量保护了一个许可集,每次应用时执行acquire()从Semaphore获取许可,如果没有则会阻塞,每次应用完执行release()开释许可。北京java培训应用场景:Semaphore对用于对资源的管制,比方数据连贯无限,应用Semaphore限度拜访数据库的线程数。
public void latch() throws InterruptedException, IOException { int count = 5; Semaphore semaphore = new Semaphore(1); ExecutorService executorService = Executors.newFixedThreadPool(count); for (int x=0;x<count;x++){ executorService.execute(new Worker(x,semaphore)); } System.in.read(); } class Worker extends Thread { Integer start; Semaphore semaphore; public Worker(Integer start, Semaphore semaphore) { this.start = start; this.semaphore = semaphore; } @Override public void run() throws IllegalArgumentException { try { System.out.println(start + " 筹备执行"); TimeUnit.SECONDS.sleep(1); semaphore.acquire(); System.out.println(start + " 曾经执行"); semaphore.release(); System.out.println(start + " 曾经开释"); } catch (InterruptedException e) { e.printStackTrace(); } } }输入如下:
0 筹备执行2 筹备执行1 筹备执行3 筹备执行4 筹备执行2 曾经执行2 曾经开释4 曾经执行4 曾经开释1 曾经执行1 曾经开释0 曾经执行0 曾经开释3 曾经执行3 曾经开释ExchangerExchanger 用于两个线程间的数据交换,它提供一个同步点,在这个同步点两个线程能够替换彼此的数据。应用场景:两个线程互相期待处理结果并进行数据传递。
public void latch() throws InterruptedException, IOException { int count = 5; Exchanger<String> exchanger = new Exchanger<>(); ExecutorService executorService = Executors.newFixedThreadPool(count); for (int x=0;x<count;x++){ executorService.execute(new Worker(x,exchanger)); } System.in.read(); } class Worker extends Thread { Integer start; Exchanger<String> exchanger; public Worker(Integer start, Exchanger<String> exchanger) { this.start = start; this.exchanger = exchanger; } @Override public void run() throws IllegalArgumentException { try { System.out.println(Thread.currentThread().getName() + " 筹备执行"); TimeUnit.SECONDS.sleep(start); System.out.println(Thread.currentThread().getName() + " 期待替换"); String value = exchanger.exchange(Thread.currentThread().getName()); System.out.println(Thread.currentThread().getName() + " 替换失去数据为:"+value); } catch (InterruptedException e) { e.printStackTrace(); } } }输入如下:
pool-1-thread-1 筹备执行pool-1-thread-1 期待替换pool-1-thread-3 筹备执行pool-1-thread-2 筹备执行pool-1-thread-5 筹备执行pool-1-thread-4 筹备执行pool-1-thread-2 期待替换pool-1-thread-1 替换失去数据为:pool-1-thread-2pool-1-thread-2 替换失去数据为:pool-1-thread-1pool-1-thread-3 期待替换pool-1-thread-4 期待替换pool-1-thread-4 替换失去数据为:pool-1-thread-3pool-1-thread-3 替换失去数据为:pool-1-thread-4pool-1-thread-5 期待替换Exchanger必须成对呈现,否则会像下面代码执行后果那样,pool-1-thread-5始终阻塞期待与其替换数据的线程,为了防止这一景象,能够应用exchange(V x, long timeout, TimeUnit unit)设置最大期待时长。