Java : wait() 从同步块中释放锁吗?
2022-08-31 13:25:10
我的印象是wait()释放所有锁,但我找到了这篇文章,上面写着
“在同步方法中调用等待是获取固有锁的简单方法”
请澄清我有点困惑。
http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
我的印象是wait()释放所有锁,但我找到了这篇文章,上面写着
“在同步方法中调用等待是获取固有锁的简单方法”
请澄清我有点困惑。
http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
“在同步方法中调用等待是获取固有锁的简单方法”
这句话是错误的,它是文档中的错误。
线程在进入同步方法时获取内部锁。同步方法中的线程设置为锁的所有者,并且处于 RUNNABLE 状态。任何尝试进入锁定方法的线程都将变为 BLOCKED。
当线程调用等待时,它会释放当前对象锁(它保留来自其他对象的所有锁),并且比进入等待状态。
当其他一些线程调用通知或 notifyAll 在同一对象上,第一个线程的状态从“等待”更改为“已阻止”,通知线程不会自动重新获取锁或变为 RUNNABLE,实际上它必须与所有其他被阻止的线程争夺锁。
等待和已阻止状态都阻止线程运行,但它们非常不同。
等待线程必须通过来自其他线程的通知显式转换为阻塞线程。
等待永远不会直接进入RUNNABLE。
当 RUNNABLE 线程释放锁(通过离开监视器或等待)时,一个被阻塞的线程会自动取代它的位置。
因此,总而言之,线程在进入同步方法或在等待后重新进入同步方法时获取锁。
public synchronized guardedJoy() {
// must get lock before entering here
while(!joy) {
try {
wait(); // releases lock here
// must regain the lock to reentering here
} catch (InterruptedException e) {}
}
System.out.println("Joy and efficiency have been achieved!");
}
我准备了一个小的测试类(一些非常脏的代码,对不起),以演示等待实际上释放了锁。
public class Test {
public static void main(String[] args) throws Exception {
testCuncurrency();
}
private static void testCuncurrency() throws InterruptedException {
Object lock = new Object();
Thread t1 = new Thread(new WaitTester(lock));
Thread t2 = new Thread(new WaitTester(lock));
t1.start();
t2.start();
Thread.sleep(15 * 1000);
synchronized (lock) {
System.out.println("Time: " + new Date().toString()+ ";" + "Notifying all");
lock.notifyAll();
}
}
private static class WaitTester implements Runnable {
private Object lock;
public WaitTester(Object lock) {
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
System.out.println(getTimeAndThreadName() + ":only one thread can be in synchronized block");
Thread.sleep(5 * 1000);
System.out.println(getTimeAndThreadName() + ":thread goes into waiting state and releases the lock");
lock.wait();
System.out.println(getTimeAndThreadName() + ":thread is awake and have reacquired the lock");
System.out.println(getTimeAndThreadName() + ":syncronized block have finished");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static String getTimeAndThreadName() {
return "Time: " + new Date().toString() + ";" + Thread.currentThread().getName();
}
}
在我的计算机上运行此类将返回下一个结果:
Time: Tue Mar 29 09:16:37 EEST 2016;Thread-0:only one thread can be in synchronized block
Time: Tue Mar 29 09:16:42 EEST 2016;Thread-0:thread goes into waiting state and releases the lock
Time: Tue Mar 29 09:16:42 EEST 2016;Thread-1:only one thread can be in synchronized block
Time: Tue Mar 29 09:16:47 EEST 2016;Thread-1:thread goes into waiting state and releases the lock
Time: Tue Mar 29 09:16:52 EEST 2016;Notifying all
Time: Tue Mar 29 09:16:52 EEST 2016;Thread-1:thread is awake and have reacquired the lock
Time: Tue Mar 29 09:16:57 EEST 2016;Thread-1:syncronized block have finished
Time: Tue Mar 29 09:16:57 EEST 2016;Thread-0:thread is awake and have reacquired the lock
Time: Tue Mar 29 09:17:02 EEST 2016;Thread-0:syncronized block have finished