整数值未刷新

时间:2019-05-09 10:59:56

标签: java multithreading

我正在尝试使用两个单独的线程打印偶数和奇数,这两个线程通过等待和通知相互通信。

我确实知道我指的是堆中的Integer对象。因此,一个线程所做的更改应该对两个线程都可见。我也使用volatile关键字声明Integet i。

即使变量i递增后,我似乎也无法理解变量i的值如何显示为1。

代码输出为

 Even Thread got lock i=1
 Even Thread waiting.. i=1
 Odd Thread got lock i=1
Odd Thread  : i=2
 Odd Thread Run called NotifyAll
 Odd Thread got lock i=2
 Odd Thread waiting.. i=2
 Even Thread woken up.. i=1
 Even Thread waiting.. i=1
package programs;


public class EvenOdd {
    static Object lck = new Object();
    volatile static Integer i=1;
    volatile static Integer N = 1000;
    public static void main(String args[]){
        EvenRunner e = new EvenRunner(lck, i, N);
        OddRunner o = new OddRunner(lck, i, N);
        Thread t1 = new Thread(e,"Even Thread ");
        Thread t2 = new Thread(o,"Odd Thread ");

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        }catch(InterruptedException ex) {
            System.out.println("Interrupted : "+ex);
        }

    }
}
class EvenRunner implements Runnable{
    Object lck;
    Integer i;
    Integer N;
    EvenRunner(Object lck,Integer i,Integer N){
        this.lck=lck;
        this.i=i;
        this.N=N;
    }
    @Override
    public void run() {


        while(i<N) {

            synchronized(lck) {
                System.out.println(" Even Thread got lock i="+i);
                while(i%2==1){
                    try {
                        System.out.println(" Even Thread waiting.. i="+i);
                        lck.wait();
                        System.out.println(" Even Thread woken up.. i="+i);
                    }catch(InterruptedException e) {
                        System.out.println("Interrupted thread : "+e);
                    }
                }

                ++i;
                System.out.println(Thread.currentThread().getName()+" : i="+i);

                System.out.println(" Even Thread Run called NotifyAll");
                lck.notifyAll();
            }
        }
    }
}
class OddRunner implements Runnable{
    Object lck;
    Integer i;
    Integer N;
    OddRunner(Object lck,Integer i,Integer N){
        this.lck=lck;
        this.i=i;
        this.N=N;
    }
    @Override
    public void run() {
        while(i<N) {
            synchronized(lck) {
                System.out.println(" Odd Thread got lock i="+i);
                while(i%2==0){
                    try {
                        System.out.println(" Odd Thread waiting.. i="+i);
                        lck.wait();
                        System.out.println(" Odd Thread woken up.. i="+i);

                    }catch(InterruptedException e) {
                        System.out.println("Interrupted thread : "+e);
                    }
                }

                ++i;
                System.out.println(Thread.currentThread().getName()+" : i="+i);

                System.out.println(" Odd Thread Run called NotifyAll");
                lck.notifyAll();
            }
        }
    }
}

预期结果:应该是其他线程在将变量I递增后也应将其值视为2。

实际结果:变量i的值即使在递增后也被其他线程读取为1。

1 个答案:

答案 0 :(得分:5)

  

预期的输出应该是其他线程在将变量I递增后也将变量I的值视为2。

构造evenRunneroddRunner时,会将相同的Integer引用作为实例字段复制到每个类中。

但是Integer是不可变的-执行++i;会将字段更改为引用不同 Integer对象。它不会修改现有整数对象的内容...因此,您的两个线程在完全独立的字段上运行,并且根本不会交互。

如果您想拥有两个线程都可以修改的单个对象,请改用AtomicInteger