简体   繁体   English

如果我有一个Runnable和一个实现线程的线程,如何使用wait()和notify()?

[英]How do I use wait() and notify() if I have one Runnable and one that implements Threads?

I want to start the second thread after the first thread has finished. 我要在第一个线程完成后开始第二个线程。 But I can't figure out how to use the wait()/notify() function if the threads are implemented differently. 但是,如果线程的实现方式不同,我无法弄清楚如何使用wait()/ notify()函数。 Tried first to use it in separate classes, but then I couldn't get the first thread to signal when it was finished. 首先尝试在单独的类中使用它,但是后来我无法让第一个线程在完成时发出信号。

public class Oblig1 {

  static void threadMessage(String message) {
    String threadName =
        Thread.currentThread().getName();
    System.out.format("%s: %s%n",
                      threadName,
                      message);
  }

  private boolean start = false;

  public void StartThread(){
    start = true;
  }

  class Thread1 implements Runnable{
    private int X;
    Thread2 obj = new Thread2(5);

    public Thread1(int x) {
      X = x;
    }

    public synchronized void run() {
      for (int i=1; i<21; i++) {
        System.out.print(X*i + " ");

        try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
          threadMessage("I wasn't done!");
        }
      }

      StartThread();
      notifyAll();
    }
  }

  class Thread2 extends Thread {
    private int X;

    public Thread2(int x) {
      X = x;
    }

    public synchronized void run() {    
      while (!start){
        try {
          wait();
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

      for (int i=1; i<21; i++) {
        System.out.print(X*i + " ");
          try {
            Thread.sleep(500);
          } catch (InterruptedException e) {
            threadMessage("I wasn't done!");
          }
        }

        notifyAll();
      }
    }


    public static void main(String [ ] args) {

        int inputT1 = 3;
        int inputT2 = 5;


        Thread t1 = new Thread(new Thread1(inputT1));
        Thread t2 = new Thread(new Thread2(inputT2));

        t1.start();
        t2.start();
  }
}

you wait on some object and you notify on some object (in your current code you don't specify object, so it is this ). 你等待某个对象,你通知某个对象(在当前的代码你不指定对象,所以它是this )。 As the result the Thread one calls notify on itself but no one is waiting for it. 结果,一个线程调用了自己的通知,但没有人在等待它。 While the Thread2 is waiting on itself but no one wakes it (as no one calls notify on this instance of Thread2). 当Thread2等待自身时,没有人唤醒它(因为没有人调用此Thread2实例的通知)。

To wake the Thread2 up, you need to call notify on that object (its this) so your Thread1 should call obj.notify() (as obj is Thread2 in your code). 要唤醒Thread2,您需要在该对象(此对象)上调用notify,以便Thread1应该调用obj.notify()(因为obj在代码中是Thread2)。

However it still won't work, as you do not pass the Thread2 instance to Thread1 (you just make a new one inside Thread1), so the thread2 you notify was just created and never started. 但是,它仍然不起作用,因为您没有将Thread2实例传递给Thread1(您只是在Thread1中创建了一个新实例),所以您通知的线程2只是创建而从未启动。 The Thread2 from your main is started but it is never notified. 主线程中的Thread2已启动,但从未收到通知。

A possible fix to your code 可能的代码修复

static class Thread1 extends Thread {
private int X;
final Thread2 second;

public Thread1(int x,Thread2 second) {
 X = x;
 this.second = second;
}

public void run() {

    for(){
    //....    
    }

    second.start = true;
    second.notify();
}
}

static class Thread2 extends Thread {
private int X;
public boolean start = false;

public Thread2(int x) {
 X = x;
}

public void run() {

    while(!start){
        synchronized(this) {
        try {
            wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    }

    for(){
        ....
    }
}
}


public static void main(String [ ] args)
{

        int inputT1 = 3;
        int inputT2 = 5;

        Thread2 t2 = new Thread2(inputT2);
        Thread1 t1 = new Thread1(inputT1,t2);


        t1.start();
        t2.start();
}

The wait() and notify() method are low-level primitives, and are best avoided in favor of higher level concurrency APIs. wait()notify()方法是低级原语,最好避免使用高级并发API。 Rolling your own concurrency code can be problematic (for instance, the start field in your code needs to be volatile!). 滚动您自己的并发代码可能会出现问题(例如,代码中的start字段必须是可变的!)。

A simple fix would be to use CountDownLatch . 一个简单的解决方法是使用CountDownLatch Replace this: 替换为:

private boolean start = false;

With this: 有了这个:

private final CountDownLatch latch = new CountDownLatch(1);

Then instead of calling notifyAll() you would call latch.countDown(); 然后,而不是调用notifyAll()而是调用latch.countDown();

Thread2's run method would look like this: Thread2的run方法如下所示:

public void run() {
  latch.await(); 

  for (int i=1; i<21; i++) {
    System.out.print(X*i + " ");
    try {
       Thread.sleep(500);
    } catch (InterruptedException e) {
      threadMessage("I wasn't done!");
    }
  }

  threadMessage("Done");
}

Example of 2 threads running one after another using lock/notify: 2个使用锁/通知依次运行的线程的示例:

public class Thread2Test {
public static void main(String[] args)
{
    final Object sync = new Object();
    final Object lock = new Object();

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized(lock) {
                synchronized(sync) {
                    sync.notify(); // Notify main() to let it start t2.
                }

                for (int n=0; n<10; n++)
                {
                    System.out.println(n);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("t1 finished.");
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("t2 started...");
            synchronized(lock) {
                // don't need to do anything but wait for lock to be released
            }
            char c = 'a';
            for (int n=0; n<10; n++)
            {
                System.out.println(c);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                c++;
            }
            System.out.println("t2 finished.");
        }
    });

    try {
        System.out.println("Wait for t1 to start...");
        synchronized(sync) {
            t1.start();
            sync.wait();
        }
    } catch (InterruptedException e) {
    }
    System.out.println("end wait");
    t2.start();
}

Note that the sync object is used to guarantee that t1 will always start before t2. 请注意,同步对象用于确保t1始终在t2之前开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM