【问题标题】:Java Thread Wait-NotifyJava 线程等待通知
【发布时间】:2010-10-20 15:03:54
【问题描述】:

我有 3 个线程(A、B、C),我无法让它们按我想要的方式工作。 所有这 3 个线程共享对同一个对象的引用 - K。 我想要做的是启动所有 3 个,然后在某个时间点,当线程 A 到达某个状态时,暂停线程 B 和 C,直到 A 执行某个方法 work() 并且当工作完成时,恢复B 和 C。

现在我的代码中有什么: 线程 A 引用了 B 和 C。 B 和 C 有一个方法 pause() { synchronized(K) { k.wait; }} 当 A 到达某种状态时,我调用 FROM A 的 run() 方法:B.pause()、C.pause()。 现在我期待的是线程 B 和 C 将等待,直到有人发出:k.notifyAll(),但是线程 A 停止了。这在java中正常吗?

代码:

class A implements Runnable {
   private K k;
   private B b;
   private C c;

   void run() {
      while(something) {
         //do something
         b.pause();
         c.pause();
          // !!! here this thread will freeze and doSomething2 wont get executed.
          // what i want is to pause B, C, doSomething2 to get executed and then resume B and C
         //do something2 
         synchronized(k) {
           k.notifyAll();
         }
      }
   }
}
class B implements Runnable {
   private K k;


   void run() {
      while(something) {
         //dome something
         }
      }
   }
   public pause() {
       synchronized(k) { k.wait();}
   }
}
class C implements Runnable {
   private K k;


   void run() {
      while(something) {
         //dome something
         }
      }
   }
   public pause() {
       synchronized(k) { k.wait();}
   }
}

【问题讨论】:

  • 为了让事情变得一目了然。在 B.run 类中放入 System.out.println(Thread.currentThread().getId());在 B.pause 中做同样的事情。 K.wait() 实际上是在另一个线程上等待(正如其他人提到的调用者)
  • 当你说暂停时,你的意思是立即停止还是完成你正在做的事情然后停下来等我说你可以继续?

标签: java multithreading wait notify


【解决方案1】:

您可以使用CylcicBarrier 来实现这一点。

CyclicBarrier barrier = new CyclicBarrier();

public void run() {
    new Thread(new A(barrier)).start();
    new Thread(new B(barrier)).start();

    barrier.await();  // Waits until all threads have called await()

    // Do something
}

public void A implements Runnable {
    private CyclicBarrier barrier;

    public A(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public void run() {
        barrier.await();
        // Do something.
    }
}

public void B implements Runnable {
    private CyclicBarrier barrier;

    public B(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public void run() {
        barrier.await();
        // Do something.
    }
}

【讨论】:

  • 如果可能,最好使用并发类而不是较低级别的等待/通知机制。
【解决方案2】:

当你调用 B.pause() 时,它在本地线程中执行,而不是在你调用 B 的 run 方法的线程中。 Thread 类中有一些不推荐使用的方法可以做到这一点,但它们很危险,请参见此处: http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

【讨论】:

    【解决方案3】:

    你确定你调用了 b.pause() 但声明了 B.sleep() 吗?

    很高兴看到线程构造/启动代码。

    【讨论】:

      【解决方案4】:

      您知道您正在使用 3 个不同的对象(监视器)A.k、B.k、C.k 吗?

      因此,当 B“暂停”时,它会在他们自己的监视器 (B.k) 上同步,无论如何该监视器应该是空闲的。 您的线程不会以任何方式“交流”。

      【讨论】:

      • 他确实说过他们共享对同一个对象的引用,所以应该没问题。问题是它像@Benoit Thiery 所说的那样阻塞了调用线程。
      【解决方案5】:

      A.run() 中删除对b.pause()c.pause() 的调用,并从它们自己的运行方法中调用它们。

      【讨论】:

        【解决方案6】:

        除非我误解了你的家庭作业,否则我认为你需要做的是学习如何中断线程。 B 和 C 是可中断的线程,它们需要以这样一种方式处理中断,直到它们被告知它是好的,它们才会恢复。它可能看起来像这样:

        while(true)
        {
           try
           {
              Thread.sleep(100);
              System.out.println("Thread is working normally...");
           }
           catch(InterruptedException e)
           {
              System.out.println("Thread has been interrupted, will wait till A is done...");
              try
              {
                 synchronized(monitor)
                 {
                   monitor.wait();
                 }
              }
              catch(InterruptedException e2)
              {
                 // whatever...
              }
           }
        }
        

        因此,在其自己的线程中运行的对象 A 将引用其他两个线程。对象 A 将有权访问其他两个线程中的可运行对象也有权访问的共享监视器对象(我称之为monitor)。当 A 中断其他线程时,它们的可运行对象将在监视器上调用 wait()。当 A 完成后,它将在监视器上调用 notifyAll()。注意你也应该清除其他线程中的中断标志,但我把它留给你自己弄清楚 - 这很容易:)

        【讨论】:

          【解决方案7】:

          我通常不会在这方面帮助家庭作业,但我认为你无论如何都使用了错误的方法,所以我认为帮助你做一些你几乎肯定不应该做的事情没有什么害处 :)

          class A implements Runnable {
             private K k;
             private B b;
             private C c;
          
             void run() {
                while(something) {
                   //do something
                   b.pause();
                   c.pause();
                    // !!! here this thread will freeze and doSomething2 wont get executed.
                    // what i want is to pause B, C, doSomething2 to get executed and then resume B and C
                   //do something2 
                   synchronized(k) {
                     k.notifyAll();
                   }
                }
             }
          }
          class B implements Runnable {
             private K k;
             volatile boolean isPaused = false;
          
          
             void run() {
                while(something) {
                   if (isPaused) {
                     synchronized(k) { k.wait();}
                     isPaused = false;
                   }
                   //dome something
                }
             }
             public pause() {
               isPaused = true;
             }
          }
          class C implements Runnable {
             private K k;
             volatile boolean isPaused = false;
          
          
             void run() {
                while(something) {
                  if (isPaused) {
                    synchronized(k) {
                      k.wait();
                    }
                    isPaused = false;
                  }
                  //dome something
                }
             }
             public pause() {
               isPaused = true;
             }
          }
          

          我猜你真正想做的是无条件地在BC中调用k等待,然后总是在A中调用notifyAll

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-08-31
            • 1970-01-01
            • 2013-02-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多