我想在自己的眼中验证睡眠和等待之间的差异。
等待只能在同步块中完成,因为它释放了监视器锁的所有权。 睡眠与监视器锁定无关,而已经是监视器锁定所有者的线程在睡眠时不应失去其所有权。
为此我做了一个测试:
步骤:
预期结果: 线程 - A只会在8秒后重新获取锁定,当线程B最终通过退出同步块释放监视器锁定时。
实际结果。 线程 - A在5秒后获取监视器锁定。
有人可以向我解释这里发生了什么吗?
public static void main(String[] args) {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("r1 before synch block");
synchronized (this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("r2 before synch block");
synchronized (this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}
编辑:
好的,我理解我的错误 - 我在等待 - r1 / r2,而不是在同一个对象上。
现在我更改了它并且都获取了同一个对象 - Main的类实例。 1. r1获得Main.this监控锁的所有权 2. r1发布它。 3.当r1尝试重新获取它时,我得到一个例外:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at Main$1.run(Main.java:28)
at java.lang.Thread.run(Unknown Source)
on synchronized (Main.this)
这里有什么问题?
public static void main(String[] args) {
Main main = new Main();
main.test();
}
public void test() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("r1 before synch block");
synchronized (Main.this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("r2 before synch block");
synchronized (Main.this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}
答案 0 :(得分:2)
这两个线程实际上有两个不同的锁。假设您的类名是MyClass,将两行synchronized(this)更改为synchronized(MyClass.this),这使得两个线程保持相同的锁。
答案 1 :(得分:0)
这是一个更好的方法来使测试工作,并表明它的工作原理。 你的问题是你没有正确等待并且无缘无故地使用了Thread.currentThread()。
顺便说一句,如果你想在不丢失信号的情况下使用wait-notifier机制的信号,我建议你阅读this link。public class MAIN
{
public static void main(final String[] args)
{
final Object sync =new Object();
final long startTime=System.currentTimeMillis();
final Runnable r1=new Runnable()
{
@Override
public void run()
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 before synch block");
synchronized(sync)
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 entered synch block");
try
{
sync.wait(5000);
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 finished waiting");
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 exited synch block");
}
};
final Runnable r2=new Runnable()
{
@Override
public void run()
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 before synch block");
synchronized(sync)
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 entered synch block");
try
{
Thread.sleep(5000);
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 finished waiting");
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 exited synch block");
}
};
try
{
final Thread t1=new Thread(r1);
final Thread t2=new Thread(r2);
t1.start();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println((System.currentTimeMillis()-startTime)/1000+": Finished joining");
}
catch(final Exception e)
{
e.printStackTrace();
}
}
}