共计 5680 个字符,预计需要花费 15 分钟才能阅读完成。
JUC 就是 java.util.concurrent 包, 这个包俗称 JUC, 外面都是解决并发问题的一些货色。
该包的地位位于 java 上面的 rt.jar 包上面
4 大罕用并发工具类:
CountDownLatch
CountDownLatch 是我目前应用比拟多的类,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 已执行 | |
全副执行结束 |
Semaphore
Semaphore 信号量保护了一个许可集, 每次应用时执行 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 曾经开释 |
Exchanger
Exchanger 用于两个线程间的数据交换,它提供一个同步点,在这个同步点两个线程能够替换彼此的数据。
应用场景:两个线程互相期待处理结果并进行数据传递。
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-2 | |
pool-1-thread-2 替换失去数据为:pool-1-thread-1 | |
pool-1-thread-3 期待替换 | |
pool-1-thread-4 期待替换 | |
pool-1-thread-4 替换失去数据为:pool-1-thread-3 | |
pool-1-thread-3 替换失去数据为:pool-1-thread-4 | |
pool-1-thread-5 期待替换 |
Exchanger 必须成对呈现,否则会像下面代码执行后果那样,pool-1-thread- 5 始终阻塞期待与其替换数据的线程,为了防止这一景象,能够应用 exchange(V x, long timeout, TimeUnit unit)设置最大期待时长。