今天我们就围绕这个代码 去理解一下什么是线程安全!
class Counter { public int counter = 0; public void increase() { this.counter++; } } public class demo1 { public static void main(String[] args) throws InterruptedException { Counter count = new Counter(); Thread thread1 = new Thread(() -> { for (int i = 0; i < 5000; i++) { count.increase(); } }); Thread thread2 = new Thread(() -> { for (int i = 0; i < 5000; i++) { count.increase(); } }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(count.counter); } } 代码的执行结果 是随机的 并不是10000
一 、线程不安全?
1. 什么是线程不安全??
我们可以看上述的代码 我们想让counter通过两个线程同时对counter进行++,但是运算结果却跟我们的预期不符,这就是线程不安全的结果。
2. 为什么这个代码会出现线程不安全??
3. 线程不安全的原因总结
①抢占式执行
线程不安全的万恶之源,也要注意并不是完全随机,但在应用层程序中是没有规律的
②修改的操作不是原子的
比如修改的n变量,不是原子的,修改的时候有可能读取到的n是脏数据
③内存可见性问题
这个是JVM代码优化而带来的问题,在逻辑等效的情况下编译器会自动优化代码!
④指令序重排
二、如何让线程安全呢???--- 加锁
使用锁 synchronized
我们可以对一个对象进行加锁,让其线程安全!比如下面对上述countrer的加锁优化
class Counter { public int counter = 0; public synchronized void increase() {//这里就相当于加锁 this.counter++; } } 这样线程在调用synchronized关键字修饰的increase方法的时候 就不会发生线程的不安全
三、synchronized 关键字的使用
1. 锁方法 -- 静态方法也可以修饰
class Counter { public int counter = 0; public synchronized void increase() {//对increase这个方法加锁 this.counter++; } }
2. 锁代码块
class Counter { public int counter = 0; public void increase() { synchronized(this){//谁调用的increase方法,这个this就代表谁 this.counter++;//对这个只有一句的代码块进行加锁 } } }