2 weidwonder weidwonder 于 2014.07.15 10:56 提问

JAVA中多线程读取成员变量的重复问题

这是个模拟卖票的问题,使用一个对象实现Runnable接口建立四个线程,这个对象有100张票,四个进程同时卖,因为没使用锁,所以会出现负数票,但是为什么会出现相同的票呢?8号票卖了四次,是因为成员变量在if之后进栈保存了值?然后直接用这个num输出吗?

代码:

 class Ticket implements Runnable//extends Thread
{
    private int num = 100       public void run()//这时不能抛出异常,因为覆盖的原函数没有抛出异常,必须catch
    {
        while(true)
        {
            if(num>0)
            {
                try{
                    Thread.sleep(2);

                }
                catch(InterruptedException e){}
                System.out.println(Thread.currentThread().getName()+" sale "+num--);
            }
            else break;
        }
    }
}

class Demo
{
    public static void main(String[] args) {
        Ticket t=new Ticket();
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        Thread t3=new Thread(t);
        Thread t4=new Thread(t);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

部分输出

Thread-1 sale 12
Thread-0 sale 13
Thread-0 sale 10
Thread-1 sale 9
Thread-3 sale 9
Thread-2 sale 10
Thread-2 sale 8
Thread-1 sale 8
Thread-0 sale 8
Thread-3 sale 8
Thread-2 sale 7
Thread-1 sale 6
Thread-0 sale 5
Thread-3 sale 4
Thread-2 sale 3
Thread-1 sale 2
Thread-0 sale 1
Thread-3 sale 0
Thread-2 sale -1
Thread-1 sale -2

3个回答

woshi74
woshi74   2014.07.15 12:25
已采纳

System.out和num--是两个操作(而且这两个操作还不是原子操作,但这里先看成原子操作,比较好解释),那么,System.out输出数字后在还没num--时线程被抢占,抢占成功的另一个线程也执行到System.out,但是依旧还没执行num--,又被另一个线程抢占,以此类推,就可能得到4个8了

weidwonder
weidwonder 谢谢,
3 年多之前 回复
zyj905411
zyj905411   2014.07.17 14:38

由于没有使用同步锁,导致多个线程存在同时访问num变量,可以将关键代码改成这样:

while (true) {
    synchronized (this) {
        if (num > 0) {
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
            }
        } else {
            break;
        }
        System.out.println(Thread.currentThread().getName() + " sale " + num--);
    }

}
u010504064
u010504064   2014.07.31 09:45

将num设置为独占方式用synchronazied内置锁,因为每一个线程都会保留自己对num的副本,看上去是每个线程都拥有对num的资源,其实是错误的

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!