业务需求1:有二十人去火车站买火车票,但只有两个窗口,需要控制,同时买票只能有两个人。当2个人中任意一个买好票离开之后,等待的18个人中又会有一个人可以占用窗口买票。
拆解:20个人是不是就是20个线程;2个窗口就是资源。
实际含义:怎么控制同一时间的并发数为2。
Semaphore信号量(控制并发线程数):
应用场景:1.限流;2.资源访问需要控制(数据库连接,打印机的接口)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
/**
* 执行人物类,获取信号量和释放信号量
*/
class SemaphoreRunnable implements Runnable {
private Semaphore semaphore; //信号量
private int user; //记录第几个用户
public SemaphoreRunnable(Semaphore semaphore, int user) {
this.semaphore = semaphore;
this.user = user;
}
@Override
public void run() {
try {
//获取信号量许可
semaphore.acquire();
System.out.println("用户"+ user +"进入窗口,准备买票");
Thread.sleep((long)(Math.random()*10000));
System.out.println("用户"+ user +"买票完成,即将离开");
Thread.sleep((long)(Math.random()*10000));
System.out.println("用户"+ user +"离开窗口");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void execute(){
//定义窗口个数
final Semaphore semaphore = new Semaphore(2);
//线程池
ExecutorService threadPool = Executors.newCachedThreadPool();
//模拟20个用户买票
for(int i = 0; i < 20 ;i ++) {
//去买票
threadPool.execute(new SemaphoreRunnable(semaphore,(i+1)));
}
threadPool.shutdown();;
}
public static void main(String[] args) {
SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
semaphoreDemo.execute();
}
}
业务需求2:
公司组织周末聚餐吃饭,首先员工们(线程)各自从家里到聚餐地点,全部到齐之后,才开始一起吃东西(同步点)。假如人员没有到齐(阻塞),到的人只能够等待,直到所有人都到齐之后才开始吃饭。
CyclicBarrier(可循环的障碍物)
场景:在多线程计算数据之后,最后需要合并结果。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierDemo {
public static void main(String[] args) {
//3个人聚餐
final CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("人员全部到齐,开始拍照。。。。");
}
});
ExecutorService threadPool = Executors.newCachedThreadPool();
//模拟三个用户
for(int i = 0; i < 3; i++) {
final int user = i + 1;
Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println(user + "号到达聚餐点,当前已有" + (cb.getNumberWaiting() + 1)+"人到达");
//阻塞
cb.await();
if(user == 1)
System.out.println("拍完照后,开始吃饭。。。");
Thread.sleep((long)(Math.random()*10000));
System.out.println(user + "吃完饭,准备回家。。。");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
};
threadPool.execute(r);
}
threadPool.shutdown();
}
}
业务需求三:绑架案,目的是为了用钱来赎人
张三团伙绑架了小乔,放言要1000万来赎人,
张三团伙和大乔同时到达约定的地点,然后一手交钱,一手交人
两个线程,在同一个点(阻塞点),交换数据
Exchanger 两个线程进行交换数据
场景:1.用于2个线程交换数据
2.校对工作
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerDemo {
public static void main(String[] args) {
//交换器,交换String类型
Exchanger ec = new Exchanger();
ExecutorService threadPool = Executors.newCachedThreadPool();
//张三团伙
threadPool.execute(new Runnable(){
@Override
public void run() {
try {
String returnStr = ec.exchange("小乔");
System.out.println("绑架者用小乔交换回:" + returnStr);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//大乔
threadPool.execute(new Runnable(){
@Override
public void run() {
try {
String returnStr = ec.exchange("1000万");
System.out.println("大乔用1000万交换回:" + returnStr);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
threadPool.shutdown();
}
}
CountDownLatch 倒计时计数器,有一个任务,他需要等待其他某几个任务执行完毕之后才能执行
import java.util.concurrent.CountDownLatch;
import static com.google.common.collect.ComparisonChain.start;
public class CountDownLatchDemo {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(2);
//任务1
new Thread(){
public void run() {
try {
System.out.println("任务1正在执行任务...");
Thread.sleep((long) (Math.random() * 1000));
System.out.println("任务1执行完毕...");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run() {
try {
System.out.println("任务2正在执行任务...");
Thread.sleep((long) (Math.random() * 1000));
System.out.println("任务2执行完毕...");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
//主线程
System.out.println("等待其他2个任务执行完毕,主线程才开始执行任务" + Thread.currentThread().getName() );
try {
latch.await();
System.out.println("其他两个任务执行完毕,主线程执行任务:" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}