1.CountDownLatch从概括到实战
CountDownLatch:从理论上来讲他是个计数器,但我们程序员更喜欢叫他发令枪,他的作用是让子线程跟主线程同步执行的一个发令枪,小伙伴们如果没有理解可以看下面实战部分
实战:
注意事项:
1.CountDownLatch的初始化计数可以随意设置,只需要后期在线程中控制减到0即刻,不是必须要跟线程数设置一致,可以通过代码灵活减去
自己想出一个需求:
现在我有一个团队,他们干啥啥不行,吃饭第一名
我要罚团队中的每个人跑两圈步,跑完再次集合解散
具体代码:
public class CountDownLatchMain {
//这里的计算初始化计算数可以随意设置,只需要后期在线程中控制减到0即刻,
//可以跟线程数设置不一致没关系的
static CountDownLatch startingGun=new CountDownLatch(8);
static class work implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"跑完第一圈");
startingGun.countDown();
System.out.println(Thread.currentThread().getName()+"跑完第二圈");
startingGun.countDown();
}
}
/** 团队挨罚案例 **/
public static void main(String[] args)
throws InterruptedException {
new Thread(new work(),"小明").start();
new Thread(new work(),"小张").start();
new Thread(new work(),"小王").start();
new Thread(new work(),"小狗").start();
startingGun.await();
System.out.println("全部挨罚完毕,全体都有解散!");
}
}
运行结果:
2.CyclicBarrier从概括到实战
CyclicBarrier:这个工具类是个循环屏障,具体作用让等待线程全部到齐再继续往下执行,并将全部到齐还可以调用统计方法,以及还可以创建多个屏障循环执行,小伙伴们如果没有理解可以看下面实战部分
实战:
注意事项:
1.CyclicBarrier设定的等待触发的线程数要跟目前线程数一致,要不然会出现线程执行完了,CyclicBarrier还处于屏障阻塞阶段
自己想出一个需求:
喜羊羊与灰太狼大家庭准备去长沙南站做高铁
首先需要在高铁站等待人齐并且统计人是否齐全
人齐了之后去买票进高铁站
然后上高铁列车时再次统计人是否齐全
人齐了开始上高铁列车
具体代码:
public class CyclicBarrierMain {
//注意一点CyclicBarrier设定的等待触发的线程数要跟目前线程数一致,
//要不然会出现线程执行完了,CyclicBarrier还处于屏障阻塞阶段
static CyclicBarrier cyclicBarrier=new CyclicBarrier(4,new sum());
//汇报人数,人员是否到齐
static class sum implements Runnable{
@Override
public void run() {
System.out.println("伙伴们我们人员到齐了,确认无误!");
}
}
static class work implements Runnable{
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",已经来到了长沙南站!");
//统计人数是否齐全,等待人齐我们在一起买票进入高铁
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName()+",已经买票进入高铁站!");
//再次统计人数是否齐全,等待人齐我们在一起进入列车准备本次的旅途
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName()+",已经坐上列车,本次G-67列车准备出发,祝大家本次乘坐愉快!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Thread(new work(),"喜羊羊").start();
new Thread(new work(),"懒羊羊").start();
new Thread(new work(),"小灰灰").start();
new Thread(new work(),"灰太狼").start();
}
}
运行结果:
3.Exchange从概括到实战
Exchange:这个工具类是个两个线程互换数据的一个数据交换所,一般实际项目中用的不多,因为有局限性只能同时让两个线程数据互换
实战:
自己想出一个需求:
小明本来没有犯法,是个好人
小霸王犯了法要坐牢,是个坏人
此时小霸王以小明家人做威胁,逼迫小明去帮小霸王坐牢
具体代码:
public class ExchangeMain {
//定义ExChanger线程交换数据对象
private static Exchanger<String> exchanger=new Exchanger<>();
public static void main(String[] args) {
new Thread(()->{
try {
//小明的数据
String str=":我不认罪,我没有杀人,冤枉啊!";
//线程交换数据
str=exchanger.exchange(str);
//获取数据交换后的数据
System.out.println(Thread.currentThread().getName()+str);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"小明").start();
new Thread(()->{
try {
//小霸王的数据
String str=":我认罪,人就是我杀的,枪毙我啊!";
//线程交换数据
str=exchanger.exchange(str);
//获取数据交换后的数据
System.out.println(Thread.currentThread().getName()+str);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"小霸王").start();
}
}
运行结果:
4.Callable,Future和FutureTask从概括到实战
Future:是一个接口定义了用来管理任务的一些取消,任务的结果获取等待的一个接口
FutureTask: FutureTask就继承了Future实现了Future的接口,作用一个有返回结果集的线程任务
Callable:有返回结果集的任务定义,跟FutureTask一起使用
其实小伙伴们只需要知道这个Future这个东西就是为了弥补多线程没有返回结果集的一个工具类
实战:
自己想出一个需求:
模拟现实场景,比如微服务,我有3个系统每个系统是独立的,不同的
现在我要去
系统A拿出一个数据10
系统B拿出一个数据20
系统C拿出一个数据30
并且中断系统A任务,
最后在主线程进行B,C合并统计
具体代码:
public class FutureMain {
public static void main(String[] args)
throws Exception{
FutureTask<Integer> systemATask=new FutureTask(()->{
//具体Callable返回
while (true){
if(Thread.currentThread().isInterrupted()){
System.out.println("获取系统A任务已经被终止!");
return 0;
}
}
});
FutureTask<Integer> systemBTask=new FutureTask(()->{
//具体Callable返回
return 20;
});
FutureTask<Integer> systemCTask=new FutureTask(()->{
//具体Callable返回
return 30;
});
new Thread(systemATask).start();
new Thread(systemBTask).start();
new Thread(systemCTask).start();
//中断系统A任务,内部采用线程协调模式终止
Thread.sleep(300);
systemATask.cancel(true);
int sum=systemBTask.get()+systemCTask.get();
System.out.println("成功获取了各自系统中的数据,合计结果为:"+sum);
}
}
运行结果:
5.Semaphore从概括到实战
Semaphore:这个是个信息量管理器,他就跟我们项目中经常用到的数据库连接池一样,比如我数据库最大连接数只能同时存在10个线程,然后此时我有20个线程同时获取数据库连接,肯定是我这20个线程中只能有10个线程可以拿到数据库连接,其余的10个线程则需要等待当前正在10个正在使用数据库连接的线程归还才可以拿到数据库连接池,这个Semaphore的概念跟数据库连接池差不多.
自己想出一个需求:
实战:
注意事项:
1.Semaphore的归还这里有个坑就是归还的时候可以无限归还,小伙伴们记得控制一下
自己想出一个需求:
使用semaphore实现简单的数据库连接池
涉及到底层方面的套件字连接数据库不管他,只弄个最简单的演示
具体代码:
public class SqlConnection implements Connection {
@Overrid
public void commit() throws SQLException {
//模拟事务提交
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class SemaphoreMain {
static class SemaphoreDBPool{
LinkedList<Connection> connections=new LinkedList<>();
//这里我用了两个Semaphore是因为这里有个坑,使用Semaphore归还许可证时可以无限归还
//所以设置范围区间,只能在这个范围区间活动
Semaphore max,min;
public void initializePoolSize(int size){
max=new Semaphore(size);
min=new Semaphore(0);
while (size>0){
connections.addLast(new SqlConnection());
--size;
}
}
public Connection getConnection()
throws InterruptedException {
//交叉扭转范围区间逻辑
max.acquire();
Connection connection;
synchronized (connections){
connection=connections.removeFirst();
}
min.release();
return connection;
}
public void returnConnection(Connection connection)
throws InterruptedException {
//交叉扭转范围区间逻辑
min.acquire();
synchronized (connections){
connections.addLast(connection);
}
max.release();
}
}
static class work implements Runnable{
SemaphoreDBPool semaphoreDBPool;
public work(SemaphoreDBPool semaphoreDBPool) {
this.semaphoreDBPool = semaphoreDBPool;
}
@Override
public void run() {
try {
Connection connection=semaphoreDBPool.getConnection();
System.out.println(Thread.currentThread().getName()+"线程,已经拿到数据库连接!");
connection.commit();
semaphoreDBPool.returnConnection(connection);
System.out.println(Thread.currentThread().getName()+"线程,已经归还数据库连接!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SemaphoreDBPool semaphoreDBPool=new SemaphoreDBPool();
//设置10个连接池数量
semaphoreDBPool.initializePoolSize(10);
//启动20个线程获取数据库连接
for (int i = 0; i < 20; ++i) {
new Thread(new work(semaphoreDBPool),"线程"+(i+1)).start();
}
}
}
运行结果:
有问题的小伙伴们,欢迎提问