当前位置:网站首页>Thread Join 和Object wait 的区别
Thread Join 和Object wait 的区别
2022-07-26 09:13:00 【new hilbert()】
Object Wait的用法:
当一个线程调用wait的时候,会释放同步锁,然后该线程进入等待状态。其他挂起的线程会竞争这个锁,得到锁的继续执行。
Thread join的用法:
一个线程运行中调用另外线程的JOIN方法,则当前线程停止执行,一直等到新join进来的线程执行完毕,才会继续执行!!
Join 原理解析:
Thread 是对象:thread也是对象锁,可以被别的线程拥有和释放
synchronized:被synchronized关键字锁住的,进入这个方法,说明此时这个线程获取到了这个对象锁
wait:当一个线程调用某个对象的wait方法时,会释放这个对象的锁,然后该线程进入等待状态。对象锁里面的等待队列的线程会竞争这个锁,得到锁的继续执行, 保证了其他线程先比得到锁,继续使用,cpu调度的时候进行sleep(sleep是不会让出锁的)
Java Join 方法解析
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
public final native void wait(long timeout) throws InterruptedException;
直接调用wait 方法 能代替Join 方法吗?
答案:肯定不行的,wait 方法要配合Synchronized 一起用,wait是释放对象锁,释放对象锁的前提是获取到对象锁。进入到Synchronized代码块,代表此时此线程获取到锁了。
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
System.out.println("main start");
Thread t1 = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("test");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
//释放t1这个对象锁,让给t1线程去执行,因为t1线程也需要t1线程这个对象锁
t1.join();
System.out.println("main end");
}
}
运行结果如下:
main start
test
main end
直接调用wait()的结果,没有Synchronized 加持。因为此时线程不确定是否已经获取锁了,会报对象锁错误IllegalMonitorStateException
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
System.out.println("main start");
Thread t1 = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("test");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t1.wait();
System.out.println("main end");
}
}
运行结果
main start
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at 锁.ThreadTest.ThreadJoin.main(ThreadJoin.java:23)
test
多线程都调用t1.join 的情况分析
Join 只是说抢到锁之后,把锁让出来,加入队列中重新等待锁
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
System.out.println("main start");
Thread t1 = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("test");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
t1.join();
System.out.println(" t2 test");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t1.join();
System.out.println("main end");
}
}
结果1
main start
test
t2 test
main end
结果2
main start
test
main end
t2 test
main 线程和 t2线程 都让出了锁资源,只有t1线程没有进行让出对象锁行为,可以保证t1线程是最先完成,但是t2和main线程,谁在t1线程之后获取到对象锁是不确定的
问题:Join 的本质是wait ,wait 是需要notify 唤醒的,那么是谁执行notify唤醒被join 阻塞的线程呢?
因为本身下面这段代码没有地方调用notify,唯一有可能就是t1线程做了操作,释放了线程对象锁。
public class ThreadJoin {
public static void main(String[] args) throws InterruptedException {
System.out.println("main start");
Thread t1 = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("test");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t1.wait();
System.out.println("main end");
}
}
答案: 是线程对象锁本身,线程执行完之后会调用exit 方法, exit方法 会调用 ensure_join
Thread.cpp
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
assert(this == JavaThread::current(), "thread consistency check");
...
// Notify waiters on thread object. This has to be done after exit() is called
// on the thread (if the thread is the last thread in a daemon ThreadGroup the
// group should have the destroyed bit set before waiters are notified).
ensure_join(this);
assert(!this->has_pending_exception(), "ensure_join should have cleared");
...
}
ensure_join方法中,调用 lock.notify_all(thread); 唤醒所有等待thread线程对象锁的线程,意味着调用了join方法被阻塞的线程都会被唤醒。
static void ensure_join(JavaThread* thread) {
// We do not need to grap the Threads_lock, since we are operating on ourself.
Handle threadObj(thread, thread->threadObj());
assert(threadObj.not_null(), "java thread object must exist");
ObjectLocker lock(threadObj, thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
// Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED.
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
// Clear the native thread instance - this makes isAlive return false and allows the join()
// to complete once we've done the notify_all below
java_lang_Thread::set_thread(threadObj(), NULL);
lock.notify_all(thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
}
边栏推荐
- mysql函数
- 力扣题DFS
- CF1481C Fence Painting
- Server memory failure prediction can actually do this!
- codeforces dp合集
- Day06 homework - skill question 7
- Horizontal comparison of the data of the top ten blue chip NFTs in the past half year
- “could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32” 问题处理
- Mutual transformation of array structure and tree structure
- Stm32+mfrc522 completes IC card number reading, password modification, data reading and writing
猜你喜欢

Numpy Foundation

高数 | 武爷『经典系列』每日一题思路及易错点总结

Node-v download and application, ES6 module import and export

TCP solves the problem of short write

优秀的 Verilog/FPGA开源项目介绍(三十零)- 暴力破解MD5

原根与NTT 五千字详解

NPM add source and switch source

Form form

QtCreator报错:You need to set an executable in the custom run configuration.

Datawhale panda book has been published!
随机推荐
redis原理和使用-基本特性
Two tips for pycharm to open multiple projects
Unity topdown character movement control
Canal 的学习笔记
NFT与数字藏品到底有何区别?
2B and 2C
Pat grade a a1013 battle over cities
Vertical search
ext3文件系统的一个目录下,无法创建子文件夹,但可以创建文件
Introduction to excellent verilog/fpga open source project (30) - brute force MD5
volatile 靠的是MESI协议解决可见性问题?(下)
[use of final keyword]
本地缓存
公告 | FISCO BCOS v3.0-rc4发布,新增Max版,可支撑海量交易上链
Li Mu D2L (VI) -- model selection
Center an element horizontally and vertically
围棋智能机器人阿法狗,阿尔法狗机器人围棋
ext4文件系统打开了DIR_NLINK特性后,link_count超过65000的后使用link_count=1来表示数量不可知
The Child and Binary Tree-多项式开根求逆
Announcement | FISCO bcos v3.0-rc4 is released, and the new Max version can support massive transactions on the chain