我有两个线程在运行:主线程和子线程。他们所做的活动是:
wait
和notify
)。它还输出子线程状态。以下是代码部分。
class MainThread {
public static void main(String[] args) throws InterruptedException {
ThreadB b = new ThreadB();
b.setName("Child thread: ");
b.start();
synchronized(b) {
System.out.print("\nwaiting for b to complete\n");
b.wait();
System.out.print("\nno more wait .........................\n");
for (int i = 0; i < 1000; i++)
System.out.print("\n" + b.getName() + "'s state:" + b.getState());
}
Thread.sleep(1000);
System.out.print("\n" + b.getName() + "state:" + b.getState());
System.out.print("\ntotal in " + Thread.currentThread().getName() + "is :" + b.total);
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {
for (int i = 0; i < 100; i++)
total += i;
System.out.println(this.getName() + "finished sum, lets notify other objects");
notify();
System.out.println(this.getName() + " done with notify and sync block\n");
}
System.out.println(this.getName() + " : entered non critical section");
for(int j = 0; j < 1000; j++) {
System.out.print("Hi ");
}
}
}
"Hi "
。但是我的观察结果是:在执行"Hi "
(对于非同步块中的循环)时,有时孩子的状态为RUNNABLE
,而且大部分时间都是BLOCKED
。例如:
Child thread: 's state:RUNNABLE Hi Hi Hi
Child thread: 's state:BLOCKED Hi Hi Hi Hi
在执行非同步块时,导致子线程进入BLOCKED
状态的原因是什么?
答案 0 :(得分:4)
两个线程无法同时打印到同一设备。如果他们尝试,其中一个将被阻止。
答案 1 :(得分:0)
这两个线程在ThreadB上没有相互同步,而是在System.out
Printstream的write方法上同步,该方法有一个synchronized块,因此一次只有一个线程可以写入流。
public void write(int b) {
try {
synchronized (this) {
ensureOpen();
out.write(b);
if ((b == '\n') && autoFlush)
out.flush();
}
}
答案 2 :(得分:0)
我不确定我完全理解你的问题。你是说儿童线程挂起? (即,你是说它永远被阻止?)如果是这样,那可能是丢失的通知。
您的程序包含数据竞争。在主线程调用b.start()
之后,两个线程竞争在新ThreadB
对象上进行同步。如果ThreadB
线程赢得比赛,它将进入同步块,最多计数100,调用this.notify()
然后退出。
只要ThreadB
线程退出synchronized
块,MainThread
线程就可以进入其synchronized
块,并呼叫b.wait()
。 b.wait()
调用永远不会返回,因为没有其他线程可以调用b.notify()
:ThreadB
线程已经完成并且已经消失了。
如果没有其他线程已经在等待,则对b.notify()
的调用根本不会执行任何内容。对象b
不记得已通知。
wait()
和notify()
方法是低级基元,旨在以非常特定的方式使用。有关详细信息,请参阅Oracle Guarded Blocks Tutorial。
答案 3 :(得分:-1)
有时ThreadB
的运行速度比主线程快,并首先获得同步(此)。在这种情况下,它应该适用于您的方案。但有时主线程在同步(b)中运行得更快。然后ThreadB
被主线程阻止,而主线程又等待来自b的通知。
尝试从主线程中删除同步块,仅在b.wait()
上进行中继。