我是多线程技术的新手,对一个小问题深表歉意。我无法在下面的代码中找到问题所在。我正进入(状态
0-Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
我要达到的目的
我正在尝试创建一个工作线程数组,每个工作线程都将打印为该特定
Thread
对象设置的值。我希望线程等待轮到他们,然后它们将执行代码并更新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();
}
}
}
}
}
最佳答案
您执行synchronized (NThread.baton)
,但是然后在该同步部分内,使用baton
更改NThread.baton = (NThread.baton+1) % TestUtil.N;
对象引用。由于现在在baton
中有一个新的对象引用,因此您不再锁定它,因此,当您下次调用baton.notifyAll()
时,它位于一个尚未同步的对象上,因此IllegalMonitorStateException
。
要解决此问题,您需要从触发器(您的final
)中分离出同步对象(并使用baton
使其不可变-始终是一个好规则)。即只有一个static final Object monitor = new Object();
,您可以对其进行同步,等待和通知,并保留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");
}
}
通常,这需要进行更多的重构,例如将通用监视器,警棍和参与者数量注入(inject)Runnable的构造函数中,以防止将这些字段公开(通常使用某种自定义类来包含所有字段)。我没有走那么远,所以您可以看到原始代码的链接。
作为单独的脚注,更好的做法是不要重写
Thread
和run
,而是从线程对象中分离出您的操作,然后使ThreadB
实现Runnable
,然后将其提供给Thread
的构造函数。关于java - baton.notifyAll给出java.lang.IllegalMonitorStateException尽管同步( bat ),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32334368/