尝试从共享资源中打印偶数和奇数

时间:2015-09-24 10:04:18

标签: java android multithreading

我正在尝试使用两个线程打印一个同步的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();
            }
        });
    }
}

2 个答案:

答案 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--;
    }
}