簡體   English   中英

如果我有一個Runnable和一個實現線程的線程,如何使用wait()和notify()?

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

我要在第一個線程完成后開始第二個線程。 但是,如果線程的實現方式不同,我無法弄清楚如何使用wait()/ notify()函數。 首先嘗試在單獨的類中使用它,但是后來我無法讓第一個線程在完成時發出信號。

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();
  }
}

你等待某個對象,你通知某個對象(在當前的代碼你不指定對象,所以它是this )。 結果,一個線程調用了自己的通知,但沒有人在等待它。 當Thread2等待自身時,沒有人喚醒它(因為沒有人調用此Thread2實例的通知)。

要喚醒Thread2,您需要在該對象(此對象)上調用notify,以便Thread1應該調用obj.notify()(因為obj在代碼中是Thread2)。

但是,它仍然不起作用,因為您沒有將Thread2實例傳遞給Thread1(您只是在Thread1中創建了一個新實例),所以您通知的線程2只是創建而從未啟動。 主線程中的Thread2已啟動,但從未收到通知。

可能的代碼修復

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();
}

wait()notify()方法是低級原語,最好避免使用高級並發API。 滾動您自己的並發代碼可能會出現問題(例如,代碼中的start字段必須是可變的!)。

一個簡單的解決方法是使用CountDownLatch 替換為:

private boolean start = false;

有了這個:

private final CountDownLatch latch = new CountDownLatch(1);

然后,而不是調用notifyAll()而是調用latch.countDown();

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");
}

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();
}

請注意,同步對象用於確保t1始終在t2之前開始。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM