适用于线程较少的场景,如果线程多了会造成无限套娃,有点麻烦,不够优雅
public class JoinTest {
// 用来记录啊鸡学习时间
static double year;
public static void main(String[] args) {
//线程A,练习唱跳rap
Thread threadA = new Thread(() -> {
for (year = 0.5; year <= 5; year += 0.5) {
System.out.println("开始练习唱跳rap:已练习" + year + "年");
try {
Thread.sleep(288);
} catch (InterruptedException e) {
e.printStackTrace();
}
//众所周知,练习两年半即可出道
if (year == 2.5) {
System.out.println("===========================>练习时长两年半,出道!!!");
//留意下这个break,想想如果不break会怎样
break;
}
}
});
//线程B,练习打篮球
Thread threadB = new Thread(() -> {
try {
// 让threadA线程插队,threadB执行到这儿时会被阻塞,直到threadA执行完
threadA.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开始练习打篮球");
});
// 启动线程
threadA.start();
threadB.start();
}
}
不管运行多少次,结果都一样,今天就是耶稣来了也一样,我说的
如果不break,那自然是等threadA执行完了threadB才开始执行
通过volatile
这种实现比较简单,也很好理解,但是性能不咋地,会抢占很多cpu资源,如非必要,不要用
public class VolatileTest {
//定义一个共享变量用来线程间通信,注意用volatile修饰,保证它内存可见
static volatile boolean flag = false;
static double year;
public static void main(String[] args) {
//线程A,练习唱跳rap
Thread threadA = new Thread(() -> {
while (true) {
if (!flag) {
for (year = 0.5; year <= 5; year += 0.5) {
System.out.println("开始练习唱跳rap:已练习" + year + "年");
try {
Thread.sleep(288);
} catch (InterruptedException e) {
e.printStackTrace();
}
//众所周知,练习两年半即可出道
if (year == 2.5) {
System.out.println("===========================>练习时长两年半,出道!!!");
// 通知threadB你可以执行了
flag = true;
//同样留意这个break
break;
}
}
break;
}
}
});
//线程B,练习打篮球
Thread threadB = new Thread(() -> {
while (true) {
// 监听flag
if (flag) {
System.out.println("开始练习打篮球");
break;
}
}
});
threadA.start();
threadB.start();
}
}
结果与上面第一个一样,就不展示了
关于break,我这里先不说,你先猜猜结果,再复制demo去跑跑,一定要动手
synchronized、wait()、notify()三件套
wait() 和 notify()都是Object类的通讯方法,注意一点,wait和 notify需搭配synchronized使用,注意,notify不会释放锁,至于不会释放锁体现在哪儿,这个demo下面有说明
public class SynchronizedTest {
static double year;
public static void main(String[] args) {
SynchronizedTest sync= new SynchronizedTest();
sync.execute();
}
public void execute() {
//线程A,练习唱跳rap
Thread threadA = new Thread(() -> {
synchronized (this) {
for (year = 0.5; year <= 5; year += 0.5) {
try {
System.out.println("开始练习唱跳rap:已练习" + year + "年");
Thread.sleep(288);
if (year == 2.5) {
System.out.println("===========================>练习时长两年半,出道!!!");
//唤醒等待中的threadB,但threadB不会立马执行,而是等待threadA执行完,因为notify不会释放锁
notify();
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
//线程B,练习打篮球
Thread threadB = new Thread(() -> {
synchronized (this) {
try {
wait();
System.out.println("开始练习打篮球");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//注意,一定要先启动B,不然会导致B永远阻塞
threadB.start();
threadA.start();
}
}
这个threadA里面的break一定要多想想,跑一跑你就知道啥叫不会释放锁
如果没有break,threadA在唤醒threadB后,会继续执行自己的逻辑,等自己执行完了才会释放锁,这时候threadB才开始执行
基于ReentrantLock
ReentrantLock是juc包下的并发工具,也能实现,但相对复杂,需结合Condition的await和signal,底层原理有点像上面的wait和notify
这里留个课后作业:思考一下为什么unlock要放在finally里面?
public class ReentrantLockTest {
static double year;
public static void main(String[] args) {
//实例化一个锁和Condition
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//线程A,练习唱跳rap
Thread threadA = new Thread(() -> {
lock.lock();
try {
for (year = 0.5; year <= 5; year += 0.5) {
System.out.println("开始练习唱跳rap:已练习" + year + "年");
Thread.sleep(288);
//众所周知,练习两年半即可出道
if (year == 2.5) {
System.out.println("===========================>练习时长两年半,出道!!!");
//唤醒等待中的线程
condition.signal();
//这里的break也是个彩蛋,去掉它触发隐藏关卡
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}
});
//线程B,练习打篮球
Thread threadB = new Thread(() -> {
lock.lock();
try {
//让当前线程等待
condition.await();
System.out.println("开始练习打篮球");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
//必须保证B先拿到锁,不然会导致A永远阻塞
threadB.start();
threadA.start();
}
}
基于CountDownLatch
这也是juc包下的并发工具,主要有两个常用方法,countDown和await
最后
分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。
面试经验技巧篇
- 经验技巧1 如何巧妙地回答面试官的问题
- 经验技巧2 如何回答技术性的问题
- 经验技巧3 如何回答非技术性问题
- 经验技巧4 如何回答快速估算类问题
- 经验技巧5 如何回答算法设计问题
- 经验技巧6 如何回答系统设计题
- 经验技巧7 如何解决求职中的时间冲突问题
- 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
- 经验技巧9 在被企业拒绝后是否可以再申请
- 经验技巧10 如何应对自己不会回答的问题
- 经验技巧11 如何应对面试官的“激将法”语言
- 经验技巧12 如何处理与面试官持不同观点这个问题
- 经验技巧13 什么是职场暗语
面试真题篇
- 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
- 真题详解2 某知名社交平台软件工程师笔试题
- 真题详解3 某知名安全软件服务提供商软件工程师笔试题
- 真题详解4 某知名互联网金融企业软件工程师笔试题
- 真题详解5 某知名搜索引擎提供商软件工程师笔试题
- 真题详解6 某初创公司软件工程师笔试题
- 真题详解7 某知名游戏软件开发公司软件工程师笔试题
- 真题详解8 某知名电子商务公司软件工程师笔试题
- 真题详解9 某顶级生活消费类网站软件工程师笔试题
- 真题详解10 某知名门户网站软件工程师笔试题
- 真题详解11 某知名互联网金融企业软件工程师笔试题
- 真题详解12 国内某知名网络设备提供商软件工程师笔试题
- 真题详解13 国内某顶级手机制造商软件工程师笔试题
- 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
- 真题详解15 某著名社交类上市公司软件工程师笔试题
- 真题详解16 某知名互联网公司软件工程师笔试题
- 真题详解17 某知名网络安全公司校园招聘技术类笔试题
- 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
资料整理不易,点个关注再走吧
网金融企业软件工程师笔试题
- 真题详解12 国内某知名网络设备提供商软件工程师笔试题
- 真题详解13 国内某顶级手机制造商软件工程师笔试题
- 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
- 真题详解15 某著名社交类上市公司软件工程师笔试题
- 真题详解16 某知名互联网公司软件工程师笔试题
- 真题详解17 某知名网络安全公司校园招聘技术类笔试题
- 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
[外链图片转存中…(img-GeM03IQU-1714524626485)]
资料整理不易,点个关注再走吧