可能像图片上的代码出现负数的概率不大,但在if语句后加上Thread.sleep(10);就能看到输出负数
闭关修行中......
不知道你要问什么,多个线程同时读取一个资源出现不同步问题很正常,因为可能一个线程获取值的时候另一个线程恰好在写值,这就会产生同步问题。
解决办法有很多,最笨的直接代码块上加同步,整个锁起来;好点的是用线程安全的类,比如AtomInteger这种,保证同步;如果对多线程很有研究,甚至可以只加很少的锁就能完成任务。
AtomInteger
线程的调用顺序是不保证有序的,其根本原因在于JVM协调资源时线程之间的切换。
本质原因是CPU为了提高效率会对指令进行重排序
没有对num进行同步,不能保证当前线程对num的值改之后,其他线程可以立马看到,题主可以了解下Java内存模型。 以题主的代码为例,假设执行到最后num=1,三个线程同时执行到if判断,都能判断出通过,那就有可能出现负数。
1、内存可见性2、修改的原子性
由于num是类静态变量,那么它会被存到堆中,在run()方法执行时拷贝一份副本到栈中存储,当有多个线程修改时,可能同时拿到一样的副本,但是由于执行的前后顺序,一个线程修改并写入了该变量,虽然堆中num已经发生变化,但是其他线程并不知道,它们会继续修改那份副本。然后修改后写入堆中,那这样就会覆盖之前线程的修改,进而导致状态的不一致问题。那么如果才能确保线程安全性呢。那就要确保修改num之前保证对堆区修改的可见性,修改之前再拿一份副本(即使之前已经拿过了),这个可用volatile关键字来保证。
原子性,由于num--实际执行是两个操作,那么就会存在执行顺序问题。即使在前面说过用volatilel来保证可见性。但是还会存在修改被其他线程覆盖的情形,只不过几率变小了。怎样保证原子性呢,可以采用synchronized关键字,Lock机制,以及JDK并发工具包等。对于这种情形,最简单的办法就是
private static AtomicInteger num=new AtomicInteger(100);
不知道你要问什么,多个线程同时读取一个资源出现不同步问题很正常,因为可能一个线程获取值的时候另一个线程恰好在写值,这就会产生同步问题。
解决办法有很多,最笨的直接代码块上加同步,整个锁起来;好点的是用线程安全的类,比如
AtomInteger
这种,保证同步;如果对多线程很有研究,甚至可以只加很少的锁就能完成任务。线程的调用顺序是不保证有序的,其根本原因在于JVM协调资源时线程之间的切换。
本质原因是CPU为了提高效率会对指令进行重排序
没有对num进行同步,不能保证当前线程对num的值改之后,其他线程可以立马看到,题主可以了解下Java内存模型。
以题主的代码为例,假设执行到最后num=1,三个线程同时执行到if判断,都能判断出通过,那就有可能出现负数。
1、内存可见性
2、修改的原子性
由于num是类静态变量,那么它会被存到堆中,在run()方法执行时拷贝一份副本到栈中存储,当有多个线程修改时,可能同时拿到一样的副本,但是由于执行的前后顺序,一个线程修改并写入了该变量,虽然堆中num已经发生变化,但是其他线程并不知道,它们会继续修改那份副本。然后修改后写入堆中,那这样就会覆盖之前线程的修改,进而导致状态的不一致问题。
那么如果才能确保线程安全性呢。那就要确保修改num之前保证对堆区修改的可见性,修改之前再拿一份副本(即使之前已经拿过了),这个可用volatile关键字来保证。
原子性,由于num--实际执行是两个操作,那么就会存在执行顺序问题。即使在前面说过用volatilel来保证可见性。但是还会存在修改被其他线程覆盖的情形,只不过几率变小了。怎样保证原子性呢,可以采用synchronized关键字,Lock机制,以及JDK并发工具包等。对于这种情形,最简单的办法就是