Java线程:等待和通知方法
我有一个线程调用Java线程:等待和通知方法,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我有一个线程调用wait方法,并且只有在从其他类调用notify方法时才能被唤醒: class ThreadA { public static void main(String [] args) { ThreadB b = new ThreadB(); b.start(); synchronized(b) { try { System.out.println("Wait
wait
方法,并且只有在从其他类调用notify
方法时才能被唤醒:
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(b) {
try {
System.out.println("Waiting for b to complete...");
b.wait();
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
}
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
notify();
}
}
}
a类{
公共静态void main(字符串[]args){
ThreadB=新的ThreadB();
b、 start();
已同步(b){
试一试{
System.out.println(“等待b完成…”);
b、 等待();
}捕获(中断异常e){}
System.out.println(“总计为:+b.Total”);
}
}
}
类ThreadB扩展线程{
整数合计;
公开募捐{
已同步(此){
对于(int i=0;i您可能希望为此使用java.util.concurrent.Semaphore。您可以循环并等待,直到计算出总数:
synchronized(b) {
while (total == 0) {
b.wait();
}
}
您还可以使用更高级别的抽象,例如。不要同步(线程)
,不要这样做,不要同步(线程)
。repat:no同步(线程)
:)
如果您需要等待线程“b”完成,请使用b.join(),现在您的代码可以自由挂起b.wait()
--
希望下面的源可以给你一个洞察力,同时同步(线程)/通知()我认为坏的实践。(剪切)
享受
要在下面进行处理,请确保您已接受Oracle的许可协议,请在此处找到:
Java源代码(incl),在init()中调用,自Java 1.5以来,任何Java c-tor都可以有效地调用它
private static **synchronized int** nextThreadNum() {
return threadInitNumber++;
}
//join(如果nanos>500000,millis==0,nanos>0,则方法w/nanos仅将millis增加1
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 **synchronized** void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
1) 您需要添加一些用于线程之间通信的标志,以便B可以在完成时向A发送信号。简单的布尔变量可以,只要它仅在同步块中读取和写入
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
isDone = true;
notify();
}
在这种特殊情况下,实际上没有理由在A中使用同步块-因为threadB在完成运行后不会执行任何操作,而A除了等待B之外不会执行任何操作,threadA可以简单地调用B.join()我假设您的实际用例比这更复杂。如果ThreadB
在ThreadA
之前完成了它的同步块,那么ThreadA
将在调用wait
时无限期地阻塞。它不会以某种方式被通知另一个线程已经停止完成了
问题是,您试图使用wait
和notify
的方式,但它们不是设计用来使用的。通常,wait
和notify
用于让一个线程等待某个条件为真,然后让另一个线程发出该条件可能为真的信号。例如,它们是常用的用法如下:
/* Producer */
synchronized (obj) {
/* Make resource available. */
obj.notify();
}
/* Consumer */
synchronized (obj) {
while (/* resource not available */)
obj.wait();
/* Consume the resource. */
}
上面代码工作的原因是,先运行哪个线程并不重要。如果生产者线程创建了一个资源,而没有人在obj
上等待wait
,那么当使用者运行时,它将进入while
循环,注意资源已经生成,然后跳过对wait
的调用。然后,它可以使用资源。另一方面,如果使用者首先运行,它将在while
循环中注意到资源还不可用,并将等待其他对象通知它。然后,另一个线程可以运行,生成资源,并通知使用者线程该资源可用一旦原始线程被唤醒,它将注意到循环的条件不再为真,并将消耗资源
更一般地说,Java建议您总是在循环中调用wait
,因为在这种情况下,线程可以从对wait
的调用中醒来,而不会收到任何通知。使用上述模式可以防止这种情况
在您的特定实例中,如果要确保ThreadB
在执行ThreadA
之前已完成运行,则可能需要使用Thread.join()
,它会显式阻止调用线程,直到其他线程执行为止。更一般地说,您可能需要研究Java提供的其他一些同步原语,因为它们通常比wait
和notify
更易于使用。ThreadB的run方法可以在您执行之前完成在这种情况下,由于notify调用发生在您开始等待之前,ThreadA将在等待调用中永久阻塞
一个简单的解决方法是在启动第二个线程之前在main中抓住b上的锁,以确保等待首先发生
ThreadB b = new ThreadB();
synchronized(b) {
b.start();
...
b.wait();
}
为什么要这么复杂?只需使用线程的join()函数
ThreadB b = new ThreadB();
b.start();
b.join();
// now print b.total
@templatetypedef:感谢您重新格式化(我刚刚开始这么做)。notify()是为神保留的。凡人都应该使用notifyAll()@Julius Davies,ParkSuppot.park/unpark更接近众神,notify仍然非常noobish:)@bestsss解释你自己。你是说park/unpark比wait/notify更有效吗?@Pacerier,虽然它在某一点上进行了调整,现在需要额外的内存围栏。park/unpark不需要显式同步(这很好,虽然它仍然可以使用本机互斥),但正确使用可能需要队列。对于简单的情况,park/unpark通常优于wait/notify,但没有notifyAll(请参阅关于队列的备注)。也不需要将所有内容都包装在try/catch(InterruptedException)中对于为什么不应该在另一个线程对象上同步,这个答案没有提供任何理由,也没有详细回答原始问题。templatetypede、b/c join和join()以及start()使用同步。您不想(通常)弄乱它们。答案是准确的:如果使用同步(线程)/notify()则使用b.join()你把事情搞砸了,有人在等你吗
ThreadB b = new ThreadB();
synchronized(b) {
b.start();
...
b.wait();
}
ThreadB b = new ThreadB();
b.start();
b.join();
// now print b.total