日期:2014-05-20  浏览次数:20856 次

多线程同步问题,[附简单代码]
Java code
public class ViolentAccessDemo
{
    public static void main(String args[])
    {
        ViolentObject violentObject = new ViolentObject();
        Thread thread1 = new Thread(new ThreadAccess(violentObject));
        Thread thread2 = new Thread(new ThreadAccess(violentObject));
        thread1.start();
        thread2.start();
        for(int i=0;i<10;i++)
        {
            violentObject.print();
            try{
                Thread.sleep(500);
            }catch(InterruptedException e)
            {
                
            }
        }
        
    }
}
class ViolentObject
{
    private int x;
    private int y;
    public void increase()
    {
        x++;       //我的理解是thread1执行到x++;没有执行y++退出。
        y++;        //thread2接着还是执行x++,这样的话,输出x的值肯定是x大才对,可是输出结果:
    }
    public void print()
    {
        System.out.println("x="+x+","+"y="+y);
    }
}
class ThreadAccess implements Runnable
{
    private ViolentObject violentObject;
    public ThreadAccess(ViolentObject vob)
    {
        System.out.println("this is constructor of ThreadAccess");
        this.violentObject = vob;
    }
    public void run()
    {
        while(true) violentObject.increase();
    }
}

输出结果:
this is constructor of ThreadAccess
this is constructor of ThreadAccess
x=0,y=0
x=84050630,y=89506803 //y居然比x大,这不违反规律了吗?
x=165934856,y=166907497
x=250595453,y=257923836
x=336504131,y=328009964
x=432364945,y=416151003

------解决方案--------------------
关注,是挺神气的....也许x++,和y++在运行的时候不是顺序执行的?期待高手解答.
------解决方案--------------------
因为你的使用的是同一个violentObject 对象,两个线程同时改变这个y值,
------解决方案--------------------
x++ => tmp = x + 1; //A
x = tmp; //B

当Thread1执行完A后,Thread2开始执行,假设此时x=30。
Thread2执行一段时间后,x=100, y=100,此时Thread1继续,执行B,此时tmp=31。于是出现了y > x。
------解决方案--------------------
ls的...两个线程他也是先到x在到y啊.
------解决方案--------------------
刚才说的lss,ls的我看了.似乎想起来看corejava的时候说过java很多操作不比如i++不是原子操作.是分两步的..所以多线程的时候可能会有不可预期的结果.
------解决方案--------------------
加锁并且同步,问题还的存在,只是数据的误差没有你的这个大,只是到了一定的时候才会发现数据存在误差,但是之后又回复一致,也就是x和y的值相等,我想,这个是虚拟机调度线程是不确定的,因为你的把一个线程休眠了500毫秒,再让其复活,到底是谁进入runnable状态,还得等虚拟机来分配,这个分配是根据级别和当前的等待状态来决定,及时你的线程进入了runnable状态,也不一定得到run,这就是虚拟机调度线程的时候存在的不确定性.
------解决方案--------------------
这是由于,你的ViolentObject类所对应的对象,不是线程安全的,而造成的。

如果将ViolentObject的两个方法都添加Synchronized关键字,就可以x与y的值相等。

出现这种状况(x>y),具有随机性。

我们知道,对一个变量做++运算的时候,这个变量会先从内存中读取到CPU的寄存器当中,++运算后,再将寄存器的值,回写到内存当中。

那么,在多线程对同一变量做++运算的时候,会出现数据的不同步现象。

我们知道,线程在操作系统中,是按照时间片来运行的。

如果线程1,刚把x变量,从内存中读到寄存器中,这时,时间片用完了,之后,线程2运行,把x从内存中读到寄存器,完成++运算,又回写到内存,
这样,当线程1重新获得时间片,继续刚才的++操作,然后再回写到内存,
此时,2个线程都对x做了++运算,
但是,由于两次从内存取值都是相同的所以,结果,相当于只完成了一次运算。

由于上述现象的产生具有不确定性,所以,两个变量x、y,它们的大小,也具有不确定性。

使用synchronized关键字,就会将相对应的对象上锁,当操作线程没有是放对应的锁时,其他线程是不可能访问的。

楼主还可以试一试,将x、y两个变量,在声明的时候,都添加volatile关键字,效果,可能要不什么都不加要好。
但是,添加volatile关键字的方法,无法保证在输出结果是x与y相同的值,
因为每次对两个变量都是++操作,那么,输出x与y的差值应该不超过4.
当然,不超过4只是我的理论推测,楼主有兴趣,可以试一下。

哈哈。

------解决方案--------------------
回帖是一种美德!
------解决方案--------------------
总共是3个线程在运行.
因为存取的是同一个对象,
System.out.println("x="+x+","+"y="+y)这条语句