1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。
1.CountDownLatch 实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
主要应用在当前现成需要在其他线程运行完成之后再执行。可以在每个线程(Thread/Runnable)内使用countDown()方法.
两种实现压测的方式:1.在当前线程中使用wait()【注意这里是wait(),不是await()】方法实现。这样才可以保证当前线程在其他线程执行完毕之后再进行执行。
2.在当前线程中循环创建线程对象的完成后执行countDown()方法,在每个线程对象的run()方法内执行await()方法。当标志量达到0后,当前线程会和创建的线程对象中await()方法后的代码争抢执行权。
主要方法:
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { }; //将count值减1
实例
第一种方式
package com.cyan.base.CountDownLatchTest;
import java.util.concurrent.CountDownLatch;
/**
* @Auther: Administrator
* @Date: 2018/11/27 13:35
* @Description:
*/
public class Test {
@org.junit.Test
public void test() {
int count = 10000;
CountDownLatch latch = new CountDownLatch(count);
for (int i = 0; i < count; i++) {
new MyThread(latch).start();
}
try {
latch.wait(); //!!!!! 注意这个方法
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"主方法执行啦!");
}
}
class MyThread extends Thread {
private CountDownLatch countDownLatch ;
public MyThread(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
if (countDownLatch != null) {
try {
Thread.sleep(1000);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"线程对象第一个输出");
}
}
第二种方式
调用CountDownLatch的await()方法,会使当前线程挂起,知道标示量减到0位置
package com.cyan.base.CountDownLatchTest;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Auther: Administrator
* @Date: 2018/11/27 13:35
* @Description:
*/
public class Test {
public static void main(String[] asdas) {
int count = 100;
CountDownLatch latch = new CountDownLatch(count);
for (int i = 0; i < count; i++) {
MyRunnable1 myRunnable = new MyRunnable1(latch);
new Thread(myRunnable).start();
latch.countDown();
}
System.out.println(Thread.currentThread().getName()+"主方法执行啦!");
}
}
class MyRunnable1 implements Runnable {
CountDownLatch latch ;
public MyRunnable1(CountDownLatch countDownLatch){
this.latch = countDownLatch;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"线程对象wait前+++++++++++++++++++++++++++的输出");
Thread.sleep(2000);
latch.await(); //!!!!!!!!!!! 注意这里是await()
System.out.println(Thread.currentThread().getName()+"线程对象wait后***************************的输出");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程对象第一个输出");
}
}
2.CyclicBarrier
可以重复多次使用,CountDownLatch不可重复使用。 CyclicBarrier对象可以在一轮使用完成之后,再次重新使用
也需要指定一个int,标识当指定数量的线程都执行到此处进行等待,等数量达到预定int值时,并发执行之后的逻辑。
package com.cyan.base.CyclicBarrierTest;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Auther: Administrator
* @Date: 2018/11/27 15:34
* @Description:
*/
public class Test {
public static void main(String[] args) {
int num = 50;
CyclicBarrier barrier = new CyclicBarrier(num);
ExecutorService executor = Executors.newFixedThreadPool(num);
for (int i = 0; i < num; i++) {
executor.execute(new MyRunnable(barrier));
System.out.println(Thread.currentThread().getName()+"循环添加线程进线程池");
}
System.out.println(Thread.currentThread().getName()+"主线程最后的挣扎!!!!");
}
}
class MyRunnable implements Runnable {
private CyclicBarrier barrier;
public MyRunnable(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"CyclicBarrier await()执行之前!!!!");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"CyclicBarrier await()执行之后!!!!");
}
}
3.Semaphore 信号量
主要方法: Semaphore可以控同时访问的线程个数
public void acquire() throws InterruptedException { } //获取一个许可
public void acquire(int permits) throws InterruptedException { } //获取permits个许可
public void release() { } //释放一个许可
public void release(int permits) { } //释放permits个许可
实例:
package com.cyan.base;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
int a = 10;
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < a; i++) {
new Thread(new MyRunnable(a,semaphore)).start();
}
System.out.println("当前可用许可数量为:"+semaphore.availablePermits());
}
}
class MyRunnable implements Runnable {
private int num;
private Semaphore semaphore;
public MyRunnable(int num, Semaphore semaphore) {
this.num = num;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"工人:"+this.num+" 获取了一个锁");
System.out.println(Thread.currentThread().getName()+"线程获取许可后许可数量为:"+semaphore.availablePermits());
Thread.sleep(2000);
semaphore.release();
System.out.println(Thread.currentThread().getName()+"线程获取许可后许可数量为:"+semaphore.availablePermits());
System.out.println(Thread.currentThread().getName()+"工人:" + this.num + " 释放了一个锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}