public class MyClass extends Thread
{
static Object lock1 = new Object();
static Object lock2 = new Object();

static volatile int i1, i2, j1, j2, k1, k2;

public void run()
{
while(true)
{
doit();
check();
}
}

void doit()
{
synchronized(lock1)
{
i1++;
} synchronized(lock1)
{
i2++;
} synchronized(lock2)
{
k1++;
k2++;
}

j2++;
j1++;
}

void check()
{
if(i1 != i2)
{
System.out.println("i");
}
if(j1 != j2)
{
System.out.println("j");
}
if(k1 != k2)
{
System.out.println("k");
}
}

public static void main(String[] args)
{
new MyClass().start();
new MyClass().start();
}

}高手给解释下为什么打印的结果全是“i”啊?
谢谢了!

解决方案 »

  1.   

    首先说明,打印结果并非全是“i”.而是"i","j"都会出现
    原因,main()为主线程不必多说 其他两个线程暂时成为一线程,二线程;
    一线程启动调用doit()方法,执行i1++,此时,doit()方法中所用被synchronized的代码段
    都将被一线程锁定;check()方法执行,打印“i”,因为j2++;j1++;并没有被锁,所以会执行;
    在某个时间片 二线程启动调用doit()方法,若此时被锁代码未解锁,则执行j2++;j1++; 然而当
    j2++执行,j1++未执行时被锁代码解锁,则另为一个线程也执行j2++,即j2++执行两次,而j1++执行
    一次则j1 != j2 打印“j”;由于k1++;k2++;这段代码同在一个被锁代码段内,所以k1==k2;
    最后 run()是死循环,自然线程不会停止,check()不会停止;
    到此,我暂且了解这么多,不足处见谅!
      

  2.   

    结果不是唯一的.只是两个线程刚好交替的时候i1 != i2才让打印出i.
      

  3.   

    i1++,i2++是在两个代码锁中,因此有可能执行完i1或者i2中的某个时,线程时间片用完,让出资源给另一个线程,而k1++;k2++;这段代码同在一个被锁代码段内,因此要么都执行,要么都不执行, 
    j2++;j1++;它并非独占式的资源,应该也是要都执行,个人理解,不知道是不是这样!!
      

  4.   

    一般遇到这种情况 用debug调试下 看代码怎么走的 呵呵
      

  5.   

    恩,谢谢楼上的几位这么有耐心
    我再试试,刚才试了了好多遍,打印出来的全是"i"但是把doit()方法中语句位置调整一下就会打印出"i"和"j"比如说这样void doit()
    {
    synchronized(lock1)
    {
    i1++;
    }
    j2++;
    synchronized(lock1)
    {
    i2++;
    } synchronized(lock2)
    {
    k1++;
    k2++;
    }


    j1++;
    }
    "i"和"j"就都会出现
      

  6.   

    运行结果完全取决于计算机的处理速度,3个都有可能
    j出现的可能性最大
    其次是i
    可能性最小的是k,
    我改了下代码测试(实际上分别去掉那几个system.out.println也一样可以看出效果)
     public class MyClass extends Thread
    {
        static Object lock1 = new Object();
        static Object lock2 = new Object();
        
        private static final ThreadLocal threadLocali = new ThreadLocal();
        private static final ThreadLocal threadLocalj = new ThreadLocal();
        private static final ThreadLocal threadLocalk = new ThreadLocal();
        
        Boolean i=new Boolean(true);
        Boolean j=new Boolean(true);
        Boolean k=new Boolean(true);
       
        
        static volatile int i1, i2, j1, j2, k1, k2;
        
        public void run() 
        {
            while(true)
            {
               
    doit();

                check();
            }
        }
        
        void doit() 
        {
            synchronized(lock1)
            {
                i1++;
            }
                 synchronized(lock1)
            {
                i2++;
            }        //Thread.sleep(5);
            synchronized(lock2)
            {
                k1++;
                k2++;
            }
            //Thread.sleep(5);
            
            j2++;
            j1++;
        }
        
        void check()
        {
         if (threadLocali.get()==null)
         threadLocali.set(i);
         if (threadLocalj.get()==null)
         threadLocalj.set(j);
         if (threadLocalk.get()==null)
         threadLocalk.set(k);
        
            if(i1 != i2)
            {
             Boolean i=(Boolean)threadLocali.get();
             if (i.booleanValue()) {
             System.out.println("i;"+i1+","+i2);
             i=new Boolean(false);
             threadLocali.set(i);
            
             }
            }
            if(j1 != j2)
            {
             Boolean j=(Boolean)threadLocalj.get();
             if (j.booleanValue()) {
             System.out.println("j;"+j1+","+j2);
             j=new Boolean(false);
             threadLocalj.set(j);
            
             }
            
            }
            if(k1 != k2)
            {
             Boolean k=(Boolean)threadLocalk.get();
             if (k.booleanValue()) {
              System.out.println("k;"+k1+","+k2);
             k=new Boolean(false);
             threadLocalk.set(k);
             }
            }
        }
        
        public static void main(String[] args)
        {
            new MyClass().start();
           
            new MyClass().start();
        }
        
    }