CountDownLatch第一种用法
/**
* 看大夫任务
*/
public class SeeDoctorTask implements Runnable {
private CountDownLatch countDownLatch;
public SeeDoctorTask(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
public void run() {
try {
System.out.println("开始看医生");
Thread.sleep(3000);
System.out.println("看医生结束,准备离开病房");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (countDownLatch != null)
countDownLatch.countDown();
}
}
}
/**
* 排队的任务
*/
public class QueueTask implements Runnable {
private CountDownLatch countDownLatch;
public QueueTask(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
public void run() {
try {
System.out.println("开始在医院药房排队买药....");
Thread.sleep(5000);
System.out.println("排队成功,可以开始缴费买药");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (countDownLatch != null)
countDownLatch.countDown();
}
}
}
/**
* 配媳妇去看病,轮到媳妇看大夫时
* 我就开始去排队准备交钱了。
*/
public class CountDownLaunchRunner {
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(new SeeDoctorTask(countDownLatch)).start();
new Thread(new QueueTask(countDownLatch)).start();
//等待线程池中的2个任务执行完毕,否则一直阻塞
countDownLatch.await();
System.out.println("over,回家 cost:"+(System.currentTimeMillis()-now));
}
}
CountDownLatch第二种用法
public class CountDownLaunchRunner {
static int sub = 0;
static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(1);
for(int i=0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
for(int j=0;j<1000;j++){
sub++;
}
}
System.out.println(Thread.currentThread().getName()+"sub="+sub);
}
}).start();
}
Thread.sleep(3000);
//⼀旦数字被减为0,则会将AQS中排队的线程(同步等待队列中从头到尾)依次唤醒
countDownLatch.countDown();
System.out.println("over,回家 cost:"+(System.currentTimeMillis()-now));
}
}
/Semaphore使用
/**
* @description :可用于流量控制,限制最大的并发访问数
*/
public class SemaphoreRunner {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2);
for (int i=0;i<10;i++){
new Thread(new Task(semaphore,"xiaoshui+"+i)).start();
}
}
static class Task extends Thread{
Semaphore semaphore;
public Task(Semaphore semaphore,String tname){
super(tname);
this.semaphore = semaphore;
//this.setName(tname);
}
public void run() {
try {
// semaphore.acquireUninterruptibly();
semaphore.acquire();//获取公共资源
System.out.println(Thread.currentThread().getName()+":aquire() at time:"+System.currentTimeMillis());
Thread.sleep(5000);
semaphore.release();
/* if(semaphore.tryAcquire(500,TimeUnit.MILLISECONDS)){
System.out.println(Thread.currentThread().getName()+":aquire() at time:"+System.currentTimeMillis());
Thread.sleep(5000);
semaphore.release();//释放公共资源
}else{
fallback();
}*/
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void fallback(){
System.out.println("降级");
}
}
CountDownLatch和Semaphore的区别和底层原理
CountDownLatch表示计数器,可以给CountDownLatch设置⼀个数字,⼀个线程调⽤CountDownLatch的await()将会阻塞,其他线程可以调⽤CountDownLatch的countDown()⽅法来对CountDownLatch中的数字减⼀,当数字被减成0后,所有await的线程都将被唤醒。
对应的底层原理就是,调⽤await()⽅法的线程会利⽤AQS排队,⼀旦数字被减为0,则会将AQS中排队的线程依次唤醒。
Semaphore表示信号量,可以设置许可的个数,表示同时允许最多多少个线程使⽤该信号量,通过acquire()来获取许可,如果没有许可可⽤则线程阻塞,并通过AQS来排队,可以通过release()⽅法来释放许可,当某个线程释放了某个许可后,会从AQS中正在排队的第⼀个线程开始依次唤醒,直到没有空闲许可。