【问题标题】:How to wait from thread1 until notified by thread2如何从thread1等待直到thread2通知
【发布时间】:2012-09-17 04:53:03
【问题描述】:

我是多线程的新手,在阅读有关多线程的文章时,想到编写这个花哨的多线程代码来执行以下操作。

我的计数器类如下。

class Counter {
  private int c = 0;

  public void increment() {
    System.out.println("increment value: "+c);
      c++;
  }

  public void decrement() {
      c--;
      System.out.println("decrement value: "+c);
  }

  public int value() {
      return c;
  }

}

此 Counter 对象在两个线程之间共享。 启动线程后,我需要执行以下操作。 我希望 Thread2 等到 Thread1 将 Counter 对象的计数增加 1。 完成后,线程 1 通知线程 2,然后线程 1 开始等待线程 2 将值减 1。 然后thread2启动并将值减1并再次通知thread1,然后thread2开始等待thread1。重复这个过程几次。

我怎样才能做到这一点。非常感谢。

我做了以下事情。

public class ConcurrencyExample {

  private static Counter counter;
  private static DecrementCount t1;
  private static IncrementCount t2;

  public static void main(String[] args) {
    Counter counter = new Counter();
    Thread t1 = new Thread(new IncrementCount(counter));
    t1.start();

    Thread t2 = new Thread(new DecrementCount(counter));
    t2.start();

  }

}


public class DecrementCount implements Runnable {

  private static Counter counter;

  public DecrementCount(Counter counter) {
    this.counter = counter;
  }

  @Override
  public void run() {
    for (int i = 0; i < 1000; i++) {
      counter.decrement();     
      System.out.println("decreamented");
    }
  }

}


public class IncrementCount implements Runnable {

  private static Counter counter;

  public IncrementCount(Counter counter) {
    this.counter = counter;
  }

  @Override
  public void run() {
    for (int i = 0; i < 1000; i++) {
      counter.increment();
      System.out.println("Incremented");
    }

  }

}

【问题讨论】:

  • IncrementCount 应该打电话给increment(),对吧?
  • 最简单的方法是使用一个线程。我建议您考虑使用多个线程会更快,而不是更复杂和更慢的示例。
  • @TomaszNurkiewicz 谢谢我已经解决了这个问题。
  • 为什么每个人对线程做的第一件事就是阻止它们发挥作用?

标签: java multithreading concurrency


【解决方案1】:

使用带有布尔标志的Condition

final Lock lock = new ReentrantLock();
final Condition incremented= lock.newCondition(); 
final Condition decremented= lock.newCondition(); 

将您的计数器更改为以下

说明:

我们使用了两个条件,一个是递增的,一个是递减的。基于布尔标志,我们检查是否必须等待一个条件。

 class Counter {
private int c = 0;
boolean increment = false;

final Lock lock = new ReentrantLock();
final Condition incremented = lock.newCondition();
final Condition decremented = lock.newCondition();

public void increment() throws InterruptedException {
    Lock lock = this.lock;
    lock.lock();
    try {
        while(increment)
            decremented.await();
        increment = true;           
        c++;
        System.out.println("increment value: " + c);
        incremented.signal();
    } finally {
        lock.unlock();
    }

}

public void decrement() throws InterruptedException {

    Lock lock = this.lock;
    lock.lock();
    try {
        while (!increment)
            incremented.await();
        c--;
        System.out.println("decrement value: " + c);
        increment = false;
        decremented.signal();
    } finally {
        lock.unlock();
    }
}

public int value() {
    Lock lock = this.lock;
    lock.lock();
    try {
        return c;
    } finally {
        lock.unlock();
    }
}

}

【讨论】:

  • 最初的答案没有多大用处。现在好多了。
【解决方案2】:

- 首先您的increment()decrement() 必须使用synchronized 关键字以避免竞争条件请参阅此Brian 规则

When we write a variable which has just been read by another thread, or reading a variable which is just lately written by another thread, must be using Synchronization. And those atomic statements/Methods accessing the fields' data must be also synchronized.

-JVM Thread Scheduler 控制哪个线程将进入运行状态,它会在那里停留多长时间,以及它的工作完成后它会去哪里。

- 一个Cannot be sure 线程将首先运行.....

-您也可以使用java.util.concurrent 中的SingleThreadExecutor,这样会先完成一项任务,然后再进行第二项任务。

【讨论】:

  • 你错误地引用了布赖恩的规则,无论如何它都不正确。使用挥发物也是一种解决方案。
  • @MartinSerrano 首先,如果您没有关于某些陈述错误的书面证明,请不要指出错误。其次,如果您有任何疑问,请参考 Bruce Eikle 编写的 Thinking in Java Book 的第 4 版线程章节……现在我在这里写的 BRIAN RULE 是正确的,我认为您还没有足够地使用 volatile。使字段可变并不能确保访问该字段的语句是单原子语句.....
【解决方案3】:

【讨论】:

    【解决方案4】:

    查看Semaphore。您需要两个,每个线程一个:incSemaphoredecSemaphore。在DecrementCount 做:

    for (int i = 0; i < 1000; i++) {
      decSemaphore.acquire();
      counter.decrement();     
      System.out.println("decreamented");
      incSemaphore.release();
    }
    

    对称地实现IncrementCountincSemaphore 的初始值应该是 10decSemaphore

    顺便说一句,您的Counter 也需要同步(请参阅synchronized 关键字和AtomicInteger)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多