在下面关于线程之间同步的代码中,根据生成的输出,为什么控件被转移到执行新线程,尽管为同一个对象获取了锁定" dt"在主要方法?
public class DemoThread extends Thread {
public DemoThread() {
}
public void run() {
int i=0;
synchronized(this) {
while(++i<=5) {
sum=i;
try{
sleep(1000);
System.out.println("Woke up from sleep");
if(i>=2) this.notify();
}catch(InterruptedException ie) {
ie.printStackTrace();
System.exit(1);
}
}
}
}
private static int sum;
public static void main(String... args) {
DemoThread dt = new DemoThread();
dt.start();
synchronized(dt) {
try{
System.out.println("main here");
dt.wait();
System.out.println("main here again");
System.out.println("sum = " + sum);
}catch(InterruptedException ie){
ie.printStackTrace();
System.exit(1);
}
}
}
}
输出:
main here
Woke up from sleep
Woke up from sleep
Woke up from sleep
Woke up from sleep
Woke up from sleep
main here again
sum = 5
编辑:我想我能够找到一个可能的代码流来解释输出:
1.主线程中的主线程进入同步块。
2.等待等待。锁定在dt对象上释放
3.新线程进入while循环,因为它锁定了对象dt
4.Thread.Sleep被执行,它没有释放锁
5.通知已发出但不会破坏主线程(?)
6.新主线程完成执行
如果我错了,请纠正我
答案 0 :(得分:3)
你很近:
1.主线程中的主线程进入同步块。
2.等待等待。锁定在dt对象上释放
3.新线程进入while循环,因为它锁定了对象dt
4.Thread.Sleep被执行,它没有释放锁
5.通知已发出呼叫但未唤醒主线程(?)
6.新主线程完成执行
直到第4步,这是正确的。
以下是步骤5:>
调用 notify()
并通知main()
线程
但它现在没有机会再次运行。
为什么?因为DemoThread
帖子没有释放锁。
notify()
方法确实在synchronized
语句中的循环中执行。
synchronized (this) {
while (++i <= 5) {
sum = i;
try {
sleep(1000);
System.out.println("Woke up from sleep");
if (i >= 2) {
notify();
}
} catch (InterruptedException ie) {
ie.printStackTrace();
System.exit(1);
}
}
根据Object.notify()
javadoc:
唤醒的线程将无法继续直到当前 线程放弃对此对象的锁定。被唤醒的线程会 以通常的方式与任何其他可能的线程竞争 积极竞争同步这个对象;例如, 被唤醒的线程没有可靠的特权或劣势 下一个锁定此对象的线程。
因此main()
线程只能在run()
方法DemoThread
终止时运行。
要让main()
主题再次运行,您可以在DemonThread
run()
方法,synchronized
语句和while
语句中反转。<登记/>
你还应该让这个线程稍微休眠一下,让main()
线程再次运行。
public void run() {
int i = 0;
while (++i <= 5) {
// let a chance for other threads
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
sum = i;
try {
sleep(1000);
System.out.println("Woke up from sleep");
if (i >= 2) {
notify();
}
} catch (InterruptedException ie) {
ie.printStackTrace();
System.exit(1);
}
}
}
}
现在作为i >= 2
,如前所述,其他线程会得到通知,但当线程在while
上循环然后再睡眠100 ms时,线程会离开锁,main()线程可以再次运行。
这是输出:
主要在这里
从睡梦中醒来
从睡梦中醒来
主要在这里再次
sum = 2
从睡梦中醒来
从睡梦中醒来
从睡梦中醒来
答案 1 :(得分:0)
synchronized关键字不用于控制线程的执行,它用于确保任何时候只有一个线程可以输入一个代码块。 通常,整个方法可以在{}之间进行同步或编码。
您还可以同步将在两个或多个线程之间共享的对象,通常是一些将由线程更新的数据结构,您需要确保状态是一致的而不是部分更新的。
在你的例子中,同步没有争用,如果你从示例中引入一些对象,多个线程试图从这个对象写入和读取,你将会更好地理解。