【问题标题】:Java program freezes when using wait and notifyAll使用 wait 和 notifyAll 时 Java 程序冻结
【发布时间】:2018-01-20 05:26:10
【问题描述】:

我正试图深入了解 wait 和 notifyAll 是如何工作的,并且遇到了障碍。

该程序下载一个长文本文档,启动多个线程来计算字符数,然后输出总计数。

我正在使用 wait 和 notifyAll 来控制线程执行,以便它们按字母顺序完成。这是代码。接下来我会解释这个问题。

public class Test {

    public static void main(String[] args) {
  //code that reads in the data

LongTask a = new LongTask(buffer, 'a', "Thread_a", 0);
    a.start();

LongTask b = new LongTask(buffer, 'b', "Thread_b", 1);
    b.start();

//Repeat code for all other characters

a.join();

System.out.println("Alphabet count is: " + SharedResults.getResults());

LongTask 类包含构造函数和 run()

public class LongTask extends Thread {
//Instance variables created here

//LongTask constructor
public LongTask (StringBuffer buffer, char target, String name, int turn)
{
    super(name);
    this.sharedData = sharedData;
    inputData = buffer;
    this.target = target;   
    this.turn = turn;
}


//Run method iterates through input data and counts matching characters, 
//then calls addToResults
public synchronized void run()
{
    //Thread t = Thread.currentThread();
    String name = this.getName();
    int runTurn = this.turn;
    System.out.println(name + " running - Turn " + runTurn);
    Integer count = 0;
    for (int i = 0; i < inputData.length(); i++) {
        if (inputData.charAt(i) == target) {
        count ++;   
        }
    }
    ResultsEntry newResult = new ResultsEntry(count, target);
    SharedResults.addToResults(newResult, turn);
    }
}

SharedResults 类将结果添加到 Array。 addToResults 方法执行此操作并控制同步。

public class SharedResults extends Thread{
//Code that creates array
//Code for SharedResults constructor

public synchronized static void addToResults(ResultsEntry newResult, int turn)
{   
    Integer resultsCount =  newResult.getCount();
    char resultsTarget = newResult.getTarget();
    Thread t = Thread.currentThread();

    /*
     * Turn number is compared to the size of the results array to control the
     * order of execution. 
     */
    while (turn != results.size()){ 
        try {
            System.out.println("Wait printout");
            t.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    } 
    System.out.println(t.getName() + " is adding " + newResult);
    SharedResults input = new SharedResults(resultsCount, resultsTarget);
    System.out.println("Cumulative Results are " + results);    
    t.notifyAll();      
    }

这是我在 Debug 中观看此步骤时看到的内容。 -Input 执行,所有 LongTask 线程启动

(Thread_a 应该是第一个执行 addToResults 的线程)

- 一些线程(不是 Thread_a)在 addToResults 的 while 评估中运行,并且不继续

-Thread_a 达到 while 评估并完全执行。 (现在应该轮到Thread_b了)

-Thread_e 执行“等待打印输出”(只是一个调试功能,告诉我线程何时等待),然后程序挂起。

在我看来,我没有正确设置等待。在我添加到 sysout 之前,该程序实际上(或看起来)正常工作。有什么想法吗?

【问题讨论】:

  • 锁定在这里的工作方式令人困惑。如果您使用锁来保护共享数据结构(其中数据结构使用锁定来限制对其自身的访问)而不是由线程完成锁定,那么它可以减少混乱。
  • Re,“我正在使用 wait 和 notifyAll 来控制线程执行,以便它们按字母顺序完成。”这听起来像你在错误的方向开始你的旅程。任何时候你强迫线程以特定的顺序做事,你就颠覆了线程的概念,即并发(即,没有特定的顺序)做事。
  • public synchronized void run()---这总是是个坏主意。
  • 如果t 引用Thread 对象,调用t.wait()t.notifyAll() 可能会产生令人惊讶的结果。 Thread 类将 t.wait()t.notify() 用于其自身目的。
  • 我将 Thread 名称的变量更改为 thread,所以现在方法调用是 thread.wait() 和 thread.notifyAll()。这让每个线程至少执行 addToResults。看起来命中 wait() 的线程永远不会重新启动,即使在 thread_a 命中 notifyAll() 之后也是如此。

标签: java multithreading wait notify


【解决方案1】:

回答我自己的问题,

this thread. 对此进行了报道

问题在于 notifyAll() 通知所有 该对象的 正在等待的线程。因为我在每个线程上调用 wait(),来自另一个线程的 notifyAll() 没有通知任何其他线程。

根据链接帖子的建议,我创建了一个静态同步对象,并在该对象上调用了等待和通知方法。生成的代码如下所示: private static final Object LOCK = new Object();

public static void addToResults(ResultsEntry newResult, int turn)
{   
    Integer resultsCount =  newResult.getCount();
    char resultsTarget = newResult.getTarget();
    Thread thread = Thread.currentThread();

    /*
     * Turn number is compared to the size of the results array to control the
     * order of execution. 
     */
    synchronized (LOCK){
        while (turn != results.size()){
            try {
                System.out.println(thread.getName() + " is waiting");
                LOCK.wait();
                } catch (InterruptedException e) {}
        }
            System.out.println(thread.getName() + " is adding " + newResult);
            SharedResults input = new SharedResults(resultsCount, resultsTarget);
            System.out.println("Cumulative Results are " + results);    
            LOCK.notifyAll();   
        }
        }

感谢所有评论的人!

【讨论】:

    猜你喜欢
    • 2019-01-27
    • 2011-09-11
    • 1970-01-01
    • 2012-07-08
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多