我正在尝试使用两个线程打印一个同步的Integer对象(mInt)直到10.但是其中一个线程锁定另一个线程抛出下面粘贴的异常。有人可以在这里指出我的错误。这是一个Java相关的问题,但包括“android”标签,因为我已经为Android编码,我需要在其中试用。
09-24 15:24:17.198 10621-11400 / com.sameer.android.samplecode E / AndroidRuntime:致命异常:Thread-364 进程:com.sameer.android.samplecode,PID:10621 java.lang.IllegalMonitorStateException:在notify()之前没有被线程锁定的对象 at java.lang.Object.notify(Native Method) at com.sameer.android.samplecode.MainActivity $ Even.run(MainActivity.java:55)
public class MainActivity extends AppCompatActivity {
private Integer mInt;
class Odd extends Thread {
private final String TAG = Odd.class.getSimpleName();
@Override
public void run() {
Log.i(TAG, "Odd() Started....");
synchronized (mInt) {
try {
while (mInt <= 10)
{
while (mInt % 2 != 1) {
Log.i(TAG, "Odd... Looping " + mInt);
mInt.wait();
}
mInt++;
Log.i(TAG, "Odd " + mInt);
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Odd() " + e.getMessage());
}
}
Log.i(TAG, "Odd() Ended....");
}
}
class Even extends Thread {
private final String TAG = Even.class.getSimpleName();
@Override
public void run() {
Log.i(TAG, "Even() Started....");
synchronized (mInt) {
try {
while (mInt <= 10)
{
while (mInt % 2 != 0) {
Log.i(TAG, "Even... Looping " + mInt);
mInt.wait();
}
mInt++;
Log.i(TAG, "Even " + mInt);
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Even() " + e.getMessage());
}
}
Log.i(TAG, "Even() Ended....");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInt = new Integer(0);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Even even = new Even();
even.start();
Odd odd = new Odd();
odd.start();
}
});
}
}
答案 0 :(得分:1)
当您增加mInt
时,您执行不修改当前的Integer对象,但创建一个新的整数对象。因此,对notify
的调用是在新的(未锁定的)对象上执行的。由于必须在锁定的对象上调用notify
,因此IllegalMonitorStateException
会发生。
附加备注(不是答案的一部分):
您的代码存在根本问题。您可以在mInt
两种方法的开头锁定run
。因此,只有一个线程可以进入其synchronized
块。第二个线程将等待mInt
上的锁定,直到第一个线程离开synchronized
块为止,即终止。因此,您最终会遇到死锁,因为第一个线程只递增一次,并在其synchronized
块内等待另一个线程执行下一个增量。但是,第二个线程无法执行此操作,因为它无法进入自己的synchronized
块(直到第一个线程释放mInt
上的锁)。
答案 1 :(得分:0)
谢谢马蒂亚斯!你的回答(部分)帮助我解决了我怀疑的问题,你把它钉了下来。问题在于mInt是新创建的,因此失去了参考。我通过创建一个类似于Integer的类来解决这个问题。我已粘贴下面的代码。
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Value mInt;
class Odd extends Thread {
private final String TAG = Odd.class.getSimpleName();
@Override
public void run() {
Log.i(TAG, "Odd() Started....");
synchronized (mInt) {
try {
while (mInt.get() < 10)
{
while (mInt.get() % 2 != 1) {
mInt.wait();
}
Log.i(TAG, "Odd " + mInt.get());
mInt.inc();
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Odd() " + e.getMessage());
}
}
Log.i(TAG, "Odd() Ended....");
}
}
class Even extends Thread {
private final String TAG = Even.class.getSimpleName();
@Override
public void run() {
Log.i(TAG, "Even() Started....");
synchronized (mInt) {
try {
while (mInt.get() < 10)
{
while (mInt.get() % 2 != 0) {
mInt.wait();
}
Log.i(TAG, "Even " + mInt.get());
mInt.inc();
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Even() " + e.getMessage());
}
}
Log.i(TAG, "Even() Ended....");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInt = new Value();
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mInt.set();
Even even = new Even();
even.start();
Odd odd = new Odd();
odd.start();
}
});
}
}
class Value {
private int member;
public Value() {
member = 0;
}
public int get() {
return member;
}
public void inc() {
this.member++;
}
public void set() {
this.member = 0;
}
public void dec() {
this.member--;
}
}