最后
还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
-
基于join
-
基于volatile
-
基于synchronized
-
基于reentrantLock
-
基于countDownLatch
不多逼逼,上才艺
join是Thread类的方法,底层基于wait+notify,你可以把这个方法理解成插队,谁调用谁插队,但有局限性
适用于线程较少的场景,如果线程多了会造成无限套娃,有点麻烦,不够优雅
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才开始执行
这种实现比较简单,也很好理解,但是性能不咋地,会抢占很多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是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);
最后
光给面试题不给答案不是我的风格。这里面的面试题也只是凤毛麟角,还有答案的话会极大的增加文章的篇幅,减少文章的可读性
Java面试宝典2021版
最常见Java面试题解析(2021最新版)
2021企业Java面试题精选
试题解析(2021最新版)
[外链图片转存中…(img-xVKh8mSb-1715232631829)]
[外链图片转存中…(img-FCazTKao-1715232631830)]
2021企业Java面试题精选
[外链图片转存中…(img-grhBTxJC-1715232631830)]
[外链图片转存中…(img-wdNUBkyu-1715232631831)]