System.out.println(“b run begin timer=” + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void bService() {
System.out.println("打印了BService time = " + System.currentTimeMillis());
}
}
static class ThreadC extends Thread {
private ThreadB threadB;
public ThreadC(ThreadB threadB) {
super();
this.threadB = threadB;
}
@Override
public void run() {
threadB.bService();
}
}
}
书中的解释:
由于ThreadA释放了ThreadB中的锁,所以线程ThreadC可以调用ThreadB中的同步方法,synchrd public void bService()。
================================================================
看过Join源码的都知道,其中的核心就是
if (millis == 0) { //由于上一步传入参数为0,因此调用当前判断
while (isAlive()) { //判断子线程是否存活
wait(0); //调用wait(0)方法
}
}
即,只要子线程还活着,就一直wait,阻塞当前主线程,直到被唤醒。
即join底层还是wait(),众所周知wait方法会释放锁,所以推测join也会释放锁,不过网上有很多join不释放的说法。
object.wait()和thread.join()
join()属于Thread类中,thread的对象锁,因为thread.join()这个join里面是this这个锁,也就是thread,即在主线程中调用t.join()相当于t.wait(),我们去掉join这个方法,就相当于
main(){
t.wait();
}
所以
main(){
synchronized(obj){
thread.join(); //join不释放锁
}
}
main(){
synchronized(thread){
thread.join(); //join释放锁
}
}
一句话概括:
主线程(mian) 释放掉 子线程(thread.join中的thread)这把锁
================================================================
题外话,上面看到join是wait的封装,那么wait什么时候被唤醒呢?让主线程保持运行呢?
每个线程退出的时候会调用notofyAll()方法,通知所有等待在该线程对象上的线程。
/**
-
This method is called by the system to give a Thread
-
a chance to clean up before it actually exits.
-
这个方法由系统调用,当该线程完全退出前给它一个机会去释放空间。
*/
private void exit() {
if (group != null) { //线程组在Thread初始化时创建,存有创建的子线程
group.threadTerminated(this); //调用threadTerminated()方法
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
/** Notifies the group that the thread {@code t} has terminated.
-
通知线程组,t线程已经终止。
void threadTerminated(Thread t) {
synchronized (this) {
remove(t); //从线程组中删除此线程
if (nthreads == 0) { //当线程组中线程数为0时
notifyAll(); //唤醒所有待定中的线程
}
if (daemon && (nthreads == 0) &&
(nUnstartedThreads == 0) && (ngroups == 0))
{
destroy();
}
}
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/8a17c3d598757fc112e004e72467432f.jpeg)
最后
ActiveMQ消息中间件面试专题
- 什么是ActiveMQ?
- ActiveMQ服务器宕机怎么办?
- 丢消息怎么办?
- 持久化消息非常慢怎么办?
- 消息的不均匀消费怎么办?
- 死信队列怎么办?
- ActiveMQ中的消息重发时间间隔和重发次数吗?
ActiveMQ消息中间件面试专题解析拓展:
redis面试专题及答案
- 支持一致性哈希的客户端有哪些?
- Redis与其他key-value存储有什么不同?
- Redis的内存占用情况怎么样?
- 都有哪些办法可以降低Redis的内存使用情况呢?
- 查看Redis使用情况及状态信息用什么命令?
- Redis的内存用完了会发生什么?
- Redis是单线程的,如何提高多核CPU的利用率?
Spring面试专题及答案
- 谈谈你对 Spring 的理解
- Spring 有哪些优点?
- Spring 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展
高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
[外链图片转存中…(img-fT70F6F9-1712164579760)]
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
[外链图片转存中…(img-h7srP9DM-1712164579761)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!