CountDownLatch
CountDownLatch初始化的时候给定一个计数,每次调用countDown计数减一
当计数未到达0之前调用await方法阻塞,直到计数减到0
使用场景,多用于划分任务由多个线程执行,例如,我们要写一个爬虫,需要爬取每个电影的前五页短评,可以划分五个线程来处理数据,通过latch.swait保证全部完成在返回
public class CountDownLatch {
public void latch() throws InterruptedException {
int count= 5;
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.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;
java.util.concurrent.CountDownLatch latch;
public Worker(Integer start, java.util.concurrent.CountDownLatch latch){
this.start=start;
this.latch=latch;
}
@Override
public void run() {
System.out.println(start+" 已执行");
latch.countDown();
}
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch();
countDownLatch.latch();
}
}
CyclicBarrier
允许一组线程相互等待,知道到达某个公共屏障点(common barrier point)也就是阻塞在调用cyclicBarrier.await的地方,看上去和CountDownlatch功能上类似,CountDownLatch的计数无法被重置,如果需要被重置,请考虑使用CyclicBarrier
CyclicBarrier初始化时还可以添加一个Runnable的参数,此Runnable在CyclicBarrier的数目达到后,所有其他线程被唤醒前被最后一个进入CyclicBarrier的线程执行
使用场景:类似CountDownLatc,但是CyclicBarrier提供几个CountDownBarrier没有的方法以来应付更加复杂的场景,例如:getNumberWaiting() 获取阻塞线程数量,
isBroken() 用来知道阻塞的线程是否被中断等方法。
reset() 将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个 BrokenBarrierException。
Semaphore
Semaphore 信号量维护了一个许可集,每次使用时执行acquire()从Semaphore获取许可,如果没有则会阻塞,每次使用完执行release()释放许可。
使用场景:Semaphore对用于对资源的控制,比如数据连接有限,使用Semaphore限制访问数据库的线程数。
package JUC;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* projectName:test
* name:SemaphoreTest
* description:todo
* date:2020/5/12 10:48 下午
* auther:AlexNi
*/
public class SemaphoreTest {
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();
}
}
}
public static void main(String[] args) throws IOException, InterruptedException {
SemaphoreTest test = new SemaphoreTest();
test.latch();
}
}
Exchanger
Exchanger 用于两个线程间的数据交换,它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。
使用场景: 两个线程相互等待处理结果并进行数据传递。
package JUC;
import java.io.IOException;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* projectName:test
* name:Exchanger
* description:todo
* date:2020/5/12 11:05 下午
* auther:AlexNi
*/
public class ExchangerTest {
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();
}
}
}
public static void main(String[] args) throws IOException, InterruptedException {
ExchangerTest test = new ExchangerTest();
test.latch();
}
}
Exchanger必须成对出现,否则会像上面代码执行结果那样,pool-1-thread-5一直阻塞等待与其交换数据的线程,为了避免这一现象,可以使用exchange(V x, long timeout, TimeUnit unit)设置最大等待时长