【问题标题】:java multithreading problemjava多线程问题
【发布时间】:2011-04-11 13:55:28
【问题描述】:

以下是部分代码。我很困惑为什么“通知 1”不能真正唤醒另一个正在等待的函数。

接缝与以下内容有关: 当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

为什么结果不是: 等待, 通知1, 等完结 通知2, . . .

而是: 等待, 通知1, 通知2, 通知2, . . . 通知2, 通知 2, 通知 3, 等完结 跳过等待, 跳过等待, 跳过等待, . . .

代码 { . . .

    MultiThreadContent m;

    void divideToParts(File testFile,FileInputStream fileInputStream, Object hashMachine) throws IOException, InterruptedException{

        .
        .
        .
        //run from here
        m = new MultiThreadContent(fileInputStream,(int)temp23,(int) (testFile.length()%temp23), numberOfParts, hashMachine);
        new Thread(new Read()).start();
        m.update();
    }

    class Read implements Runnable{
        @Override
        public void run() {
            try {
                m.read();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class MultiThreadContent{

        .
        .
        .


        boolean preNotReady=true;
        boolean updateNotFinished;

        //read{
            public synchronized void read() throws InterruptedException{
                //initial{
                    readNextBlock();
                    preBlock=nextBlock;
                    read_notify();
                    System.out.println("notify 1");//d
                    if(finishedRead!=true)
                    {
                        readNextBlock();
                        read_wait();
                    }
                    else
                        return;
                //}
                while(finishedRead!=true){
                    preBlock=nextBlock;
                    read_notify();
                    System.out.println("notify 2");//d
                    readNextBlock();
                    read_wait();
                }
                //closing{
                    preBlock=nextBlock;
                    read_notify();
                    System.out.println("notify 3");//d
                //}
            }
            void read_notify(){
                preNotReady=false;
                notifyAll();
            }
            void read_wait() throws InterruptedException{
                if(updateNotFinished==true)
                {
                    wait();
                    System.out.println("wait for update");//d
                }
                preNotReady=true;
            }
        //}


        //update{
            public synchronized void update() throws InterruptedException{
                for (int i = 0; i < totalParts; i++) {
                    update_wait();
                    divideToParts_update(hashMachine, preBlock);
                    update_notify();
                }
            }
            void update_notify(){
                updateNotFinished=false;
                notifyAll();
            }
            void update_wait() throws InterruptedException{
                if(preNotReady){
                    System.out.println("wait");//d
                    wait();
                    System.out.println("wait finish");//d
                }
                updateNotFinished=true;
                System.out.println("skip wait");//d
            }
        //}
    }
}

【问题讨论】:

  • finishedRead 没有定义?这是所有的代码吗?
  • 它是代码的一部分。我很困惑为什么 notifyAll 不能真正唤醒在“通知 1”处等待的另一个函数。

标签: java multithreading


【解决方案1】:

原因是你没有离开同步块。 read_wait 方法永远不会进入 if 块,因为 updateNotFinished 默认初始化为 false。由于 read_wait 永远不会进入 if 块,您将继续在 finishedRead!=true 上循环。在退出该方法和同步块之前,您将永远不会放弃对监视器的持有。

一旦你完成了,那么锁就可用并且另一个线程被正确唤醒。

要测试我在说什么,请尝试在初始化时设置updateNotFinished = true

【讨论】:

  • @John V. 但我有 updateNotFinished=true;在 update_wait() 中。但是,由于 read() 中的 nofifyAll 不会唤醒 update_wait() 中的 wait(),因此 updateNotFinished=true;命令直到很晚才运行..
  • @micahli123 您看到的问题仅仅是因为 read() 中的线程永远不会退出。同步方法确保互斥,并且 notifyAll 只有在同步块中没有其他线程时才会唤醒线程。由于您永远不会离开同步块,因此在您退出所述块之前,任何等待的线程都不会被唤醒。基本上,在第一个线程完成之前,update_wait 中的 updateNotFinished = true 永远不会被调用。
  • @John V. 在我尝试了你的测试之后,notify1 起作用了:等待通知 1 等待完成跳过等待跳过等待跳过等待跳过等待跳过等待,但我仍然不知道为什么 notify1 没有'在我的例子中不起作用..
  • @John V 我明白你的意思。我不知道它们是互斥的...但是您有什么建议可以使它们“不互斥”...我想我必须阅读一些有关中断的材料..
  • 是的,这将是一个很好的教训。多线程很难正确处理。你的想法是对的,只是你对预期会发生的事情有错误的理解。
【解决方案2】:

不知道是不是你遇到的问题,但肯定会成为问题。所有对 .wait() 的调用都必须包含在一个 while 循环中。对 wait() 的调用可以随机唤醒。

根据documentation:“在单参数版本中,中断和虚假唤醒是可能的,并且此方法应始终在循环中使用:”

【讨论】:

  • 感谢您的教导!我相信这可能是问题所在。但即使我已经纠正了这个问题仍然存在。
【解决方案3】:

我发现较新的并发库比 wait()/notify() 更易于使用。添加这些库是有原因的,它们非常值得学习。以下是如何简化代码的示例。

String filename = ...
ExecutorService es = Executors.newFixedThreadPool(5);
FileInputStream fis = new FileInputStream(filename);

while (true) {
    final byte[] buffer = new byte[8 * 1024];
    final int len = fis.read(buffer);
    if (len < 0) break;
    es.submit(new Runnable() {
        public void run() {
            process(buffer, len);
        }
    });
}
fis.close();
es.shutdown();
es.awaitTermination(60, TimeUnit.MINUTES);

【讨论】:

  • 太棒了。我会试试。看起来一样。它似乎更灵活。
猜你喜欢
  • 2016-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 2016-12-12
  • 2011-09-11
  • 1970-01-01
  • 2023-03-26
相关资源
最近更新 更多