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