线程安全问题
所谓线程安全问题,即多个线程同时对同一个变量或者资源进行读写操作而产生 脏读 的问题。
为什么会出现线程安全问题呢?我们首先要明确程序修改变量的逻辑
public class Sequcence {
private int value;
public int getNextValue(){
return value++;
}
public int getValue(){
return value;
}
public static void main(String[] args){
Sequcence c = new Sequcence();
for (int i=0;i<10;i++){
new Thread(()->{
for (int j=0;j< 500;j++){
c.getNextValue();
}
}).start();
}
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(c.getValue());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
入上述代码所示,启动10个线程,每个线程对 value
执行 500 次value++
,在我们的预期中,最终value
的值应该是5000
,但是在真实执行之后,我们发现,在大多数情况下,value
的值是小于5000
的。
线程调用getNextValue
方法执行 value++
从表面是看单个操作,但实际上**包含了三个独立的操作
- 读取
value
- 将读取到的值加1
- 将计算结果写入
value
而线程是交替执行 的,所以在执行的过程中会出现这样的情况,第一个线程读取到的value
值为1
,在将计算结果写入之前,第二个线程也读取了value
的值,此时,第二个线程读取到的value
值也为 1
,在第二个线程读取之后,第一个线程将计算结果 2
写入了val;ue
,由于第二个线程读取到的值也是1
,因此其计算结果也为2
,写入value
的值也为2
,最终两个线程执行了两次+1
的操作,但是value
的值只增加了 1
.
这种情况是一定要杜绝的,怎么才能避免这种情况发生呢?
- 当有线程在执行
getNextValue
方法时,进行锁定,在当前线程执行结束之前,其他线程只能等待,不能执行该方法 - 当有线程在
getNextValue
方法执行value++
中读取value
值时,进行锁定,在当前线程写入计算结果之前,其他线程不能执行value++
操作,必须要等待当前线程操作结束之后
synchronized
的基本使用
在方法上使用
public synchronized int getNextValue(){
return value++;
}
这种方式相当于
public int getNextValue(){
synchronized (this){
return value++;
}
}
声明一个锁对象
private Object lock = new Object();
public int getNextValue(){
synchronized (lock){
return value++;
}
}