java Runable一个现象的解释,理解不了

main方法

 public class main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket ti=new Ticket();
Thread t1=new Thread(ti);
Thread t2=new Thread(ti);
Thread t3=new Thread(ti);
Thread t4=new Thread(ti);
t1.start();
t2.start();
t3.start();
t4.start();
}
}

runable实现类

 public class Ticket implements Runnable {
    private int all=100;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            if(all>0)
            {
                System.out.println(Thread.currentThread().getName()+"ticket"+all);
                all--;
            }

            else
                break;
        }
    }

}

输出结果
Thread-0ticket100
Thread-0ticket99
Thread-0ticket98
Thread-2ticket100
Thread-2ticket96
Thread-2ticket95
Thread-2ticket94
Thread-2ticket93
Thread-2ticket92
Thread-2ticket91
Thread-2ticket90
Thread-2ticket89
Thread-2ticket88
Thread-2ticket87
Thread-2ticket86
Thread-2ticket85
Thread-2ticket84
Thread-2ticket83
Thread-2ticket82
Thread-2ticket81
Thread-2ticket80
Thread-2ticket79
Thread-2ticket78
Thread-2ticket77
Thread-2ticket76
Thread-2ticket75
Thread-2ticket74
Thread-3ticket100
Thread-3ticket72
Thread-3ticket71
Thread-1ticket100
Thread-3ticket70
Thread-2ticket73
Thread-2ticket67
Thread-2ticket66
Thread-2ticket65
Thread-2ticket64
Thread-2ticket63
Thread-2ticket62
Thread-2ticket61
Thread-2ticket60
Thread-2ticket59
Thread-2ticket58
Thread-2ticket57
Thread-0ticket97
Thread-2ticket56
Thread-3ticket68
Thread-3ticket53
Thread-3ticket52
Thread-1ticket69
Thread-3ticket51
Thread-2ticket54
Thread-0ticket55
Thread-2ticket48
Thread-3ticket49
Thread-1ticket50
Thread-3ticket45
Thread-2ticket46
Thread-0ticket47
Thread-2ticket42
Thread-2ticket40
Thread-2ticket39
Thread-2ticket38
Thread-2ticket37
Thread-2ticket36
Thread-2ticket35
Thread-2ticket34
Thread-3ticket43
Thread-1ticket44
Thread-3ticket32
Thread-2ticket33
Thread-0ticket41
Thread-2ticket29
Thread-3ticket30
Thread-1ticket31
Thread-3ticket26
Thread-3ticket24
Thread-3ticket23
Thread-3ticket22
Thread-3ticket21
Thread-3ticket20
Thread-2ticket27
Thread-2ticket18
Thread-2ticket17
Thread-2ticket16
Thread-2ticket15
Thread-2ticket14
Thread-2ticket13
Thread-2ticket12
Thread-2ticket11
Thread-2ticket10
Thread-2ticket9
Thread-2ticket8
Thread-2ticket7
Thread-2ticket6
Thread-2ticket5
Thread-2ticket4
Thread-2ticket3
Thread-2ticket2
Thread-2ticket1
Thread-0ticket28
Thread-3ticket19
Thread-1ticket25
为什么100出现了4次,非首次输出的其他输出100的时候,顶替掉了原来的数值,却在结尾输出。不是公用一个ticket的吗,为什么后面还会出现100.。。

9个回答

线程在工作时,会先从主内存中读取数据,再把all的值从主内存中拷贝一份到自己的线程内存中,然后在运行一段时间后往主内存中写入已经改变的all的值,由于线程运行是抢占式的,t1线程还没来得及通知主线程中all的值已经改变了,t2线程就已经从主内存中又拷贝了一份all的变量,所以就变成这种状况了,我个人理解的,说的不对的地方请见谅。

kpoikpok
kpoikpok 回复Android_app: 感谢补充:D
一年多之前 回复
Android_app
GZ-MK 这位同学说的很到位,另外我这边也补充下。 1、但凡类似这样的操作都是有读和写两种基本操作,在这里“从主内存中拷贝一份到自己的线程内存中”是读,“运行一段时间后”,其实是操作完成哈,“往主内存中写入”就是写操作了,在其中一个线程实例进行这三种操作的时候,在没有锁定的情况下,其他的任意线程都有可能进行和第一条线程类似的动作;这里有点绕,简单点,第一条线程做任何事,第二条线程也可以做; 2、解决方案,加上锁定即可(加同步关键字或有其他类似的做法亦可),如楼上说的volatile
一年多之前 回复

多线程处理是非原子性的操作,例如第一次all的值为100,当线程1从主内从中获取all为100,二all--并没有执行,此时线程2从祝内存中获取的all也为100
,这样就造成了数据会出现重复的

你的程序中all=30?是不是写错了,对于结果,由于多个线程共享ticket,输出的结果具有一定的随机性,比如线程1:读到all=100,还没有执行的输出,此时线程2已经读到100,
并且ticket减1,但是ticket减1之后的结果线程1并不知道,还是继续打印ticket=100,因此就有两个100;你多执行几次就会发现每次的结果会不一样的。

因为你是多线程调用ticket中的run( )方法,并没有加锁,所有有可能在Thread-0的时间片段到的时候可能是刚刚执行完循环的判断,没有输出此时的指,也没有对all的值更改。
然后Thread-1又开始执行,并行对一个不加锁的数据更改结果是随机的

因为你是多线程调用ticket中的run( )方法,并没有加锁,

加个volatile试试

使用锁来控制线程的安全

加个volatile试试,可以去看一下jmm(java 内存模型)相关的内容。

线程安全问题,可以考虑加同步锁.

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!