Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
baton.notifyAll给出java.lang.IllegalMonitorStateException,尽管已同步(baton)_Java_Multithreading - Fatal编程技术网

baton.notifyAll给出java.lang.IllegalMonitorStateException,尽管已同步(baton)

baton.notifyAll给出java.lang.IllegalMonitorStateException,尽管已同步(baton),java,multithreading,Java,Multithreading,我是多线程新手,很抱歉有个小问题。我无法在下面的代码中找到错误。我越来越 线程“thread-0”java.lang.IllegalMonitorStateException中的0-Exception 我正在努力实现的目标 我试图创建一个工作线程数组,每个工作线程将打印为特定线程对象设置的值。我希望线程等待轮到它们的时候,然后它们将执行代码并更新baton(我怀疑我做得不对)的值,然后再通知其他线程,这样循环中的下一个线程将重复该过程 这是我的密码。谢谢 package test; publ

我是多线程新手,很抱歉有个小问题。我无法在下面的代码中找到错误。我越来越

线程“thread-0”java.lang.IllegalMonitorStateException中的
0-Exception
我正在努力实现的目标

我试图创建一个工作线程数组,每个工作线程将打印为特定
线程
对象设置的值。我希望线程等待轮到它们的时候,然后它们将执行代码并更新
baton
(我怀疑我做得不对)的值,然后再通知其他线程,这样循环中的下一个线程将重复该过程

这是我的密码。谢谢

package test;

public class NThread
{
  public static Integer baton;

  public static void main(String[] args) throws InterruptedException
  {
    baton = 0;
    TestUtil.N = 2;
    runThread();
  }

  protected static void runThread() throws InterruptedException
  {
    int i;
    ThreadB b[] = new ThreadB[TestUtil.N];
    for (i = 0; i < TestUtil.N; i++)
    {
      b[i] = new ThreadB();
      b[i].val = i;
      b[i].start();
    }
  }
}

class ThreadB extends Thread
{
  public int val;

  @Override
  public void run()
  {
    synchronized (NThread.baton)
    {
      while (true)
      {
        if (NThread.baton != val)
        {
          try
          {
            NThread.baton.wait();
          }
          catch (InterruptedException e)
          {
            e.printStackTrace();
          }
        }
        else
        {
          TestUtil.printNum(val);
          NThread.baton = (NThread.baton+1) % TestUtil.N;
          NThread.baton.notifyAll();
        }
      }
    }
  }
}
封装测试;
公共类读物
{
公共静态整型指挥棒;
公共静态void main(字符串[]args)引发InterruptedException
{
指挥棒=0;
TestUtil.N=2;
runThread();
}
受保护的静态void runThread()引发InterruptedException
{
int i;
ThreadB b[]=新ThreadB[TestUtil.N];
对于(i=0;i
您确实执行了
同步(NThread.baton)
,但在该同步部分中,您使用
NThread.baton=(NThread.baton+1)%TestUtil.N更改
baton
对象引用。由于您现在在
baton
中有了一个新的对象引用,您不再锁定它,因此当您下次调用
baton.notifyAll()
时,它位于您尚未同步的对象上-因此您的
IllegalMonitorStateException

要解决这一问题,您需要从触发器(您的
指挥棒
)中分离出同步对象(并使用
final
-这始终是一个好规则,使其不可变)。i、 e.有一个
静态最终对象监视器=新对象()同步,等待并通知打开,并为数字触发器保留
baton

稍微更新的示例是:

class ThreadB implements Runnable {
    public final int val;
    public ThreadB(int val) { this.val = val; }

    @Override public void run() {
        try {
            //  synchronize outside the loop so we don't constantly lock/unlock
            synchronized (NThread.monitor) {
                while (true) { // spin until interrupted
                    while (NThread.baton != val) // handle spurious wake-ups
                        NThread.monitor.wait();
                    //  print, increment and notify
                    TestUtil.printNum(val);
                    NThread.baton = (NThread.baton + 1) % TestUtil.N;
                    NThread.monitor.notifyAll();
                }
            }
        } catch (InterruptedException e) {
            // if interrupted then we exit
        }
    }
}
运行时使用:

public class NThread {
    public static int baton;
    public static final Object monitor = new Object();

    public static void main(String[] args) throws InterruptedException {
        baton = 0;
        TestUtil.N = 2;
        runThread();
    }

    protected static void runThread() throws InterruptedException {
        int i;
        Thread b[] = new Thread[TestUtil.N];
        for (i = 0; i < b.length; i++) { // loop limit is on the array length - its clearer like that
            b[i] = new Thread(new ThreadB(i));
            b[i].start();
        }
        TimeUnit.SECONDS.sleep(1);
        for (i = 0; i < b.length; i++) b[i].interrupt();
        for (i = 0; i < b.length; i++) b[i].join();
        System.out.println("All done");
    }
}
公共类读取{
公共指挥棒;
公共静态最终对象监视器=新对象();
公共静态void main(字符串[]args)引发InterruptedException{
指挥棒=0;
TestUtil.N=2;
runThread();
}
受保护的静态void runThread()引发InterruptedException{
int i;
线程b[]=新线程[TestUtil.N];
对于(i=0;i
这通常会经历更多的重构,比如将公共监视器、指挥棒和参与者数量注入Runnable的构造函数,以防止这些字段公开(通常使用某种自定义类来包含它们)。我没有走那么远,你可以看到链接到你的原始代码

作为一个单独的脚注,更好的做法是不要覆盖
线程
运行
,而是将您的操作从线程对象中分离出来,从而使
线程B
实现
可运行
,然后将其提供给
线程
的构造函数(NThread.baton)
,但是在同步的部分中,您可以使用
NThread.baton=(NThread.baton+1)%TestUtil.N;
更改
baton
对象引用。由于您现在在
baton
中有一个新的对象引用,因此当您下次调用
baton.notifyAll()
它位于您尚未同步的对象上-因此您的
非法监视器状态异常

要解决此问题,您需要将同步对象从触发器(您的
baton
)中分离出来(并使用
final
-这始终是一个好规则,使其不可变)。即,使用单个
静态最终对象监视器=新对象()
同步,等待并通知,并为数字触发器保留
指挥棒

稍微更新的示例是:

class ThreadB implements Runnable {
    public final int val;
    public ThreadB(int val) { this.val = val; }

    @Override public void run() {
        try {
            //  synchronize outside the loop so we don't constantly lock/unlock
            synchronized (NThread.monitor) {
                while (true) { // spin until interrupted
                    while (NThread.baton != val) // handle spurious wake-ups
                        NThread.monitor.wait();
                    //  print, increment and notify
                    TestUtil.printNum(val);
                    NThread.baton = (NThread.baton + 1) % TestUtil.N;
                    NThread.monitor.notifyAll();
                }
            }
        } catch (InterruptedException e) {
            // if interrupted then we exit
        }
    }
}
运行时使用:

public class NThread {
    public static int baton;
    public static final Object monitor = new Object();

    public static void main(String[] args) throws InterruptedException {
        baton = 0;
        TestUtil.N = 2;
        runThread();
    }

    protected static void runThread() throws InterruptedException {
        int i;
        Thread b[] = new Thread[TestUtil.N];
        for (i = 0; i < b.length; i++) { // loop limit is on the array length - its clearer like that
            b[i] = new Thread(new ThreadB(i));
            b[i].start();
        }
        TimeUnit.SECONDS.sleep(1);
        for (i = 0; i < b.length; i++) b[i].interrupt();
        for (i = 0; i < b.length; i++) b[i].join();
        System.out.println("All done");
    }
}
公共类读取{
公共指挥棒;
公共静态最终对象监视器=新对象();
公共静态void main(字符串[]args)引发InterruptedException{
指挥棒=0;
TestUtil.N=2;
runThread();
}
受保护的静态void runThread()引发InterruptedException{
int i;
线程b[]=新线程[TestUtil.N];
对于(i=0;i
这通常会经历更多的重构,比如将公共监视器、指挥棒和参与者的数量注入Runnable的构造函数,以防止这些字段公开(通常使用一些k