Java多线程——深入理解"脏读"
脏读:某线程取到的数据是被其他线程所修改过的。
在Java中,若没有使用加锁操作,所有的线程之间是异步执行的,因此就会产生"脏读"导致数据的丢失或错误。
首先来看根本没有任何加锁操作的情况。
class MyThread implements Runnable{
private int num = 5;
@Override
public void run() {
showNum();
}
public void showNum(){
while (num>0){
num--;
System.out.println(Thread.currentThread().getName()+":"+num);
}
}
}
public class DirtyReadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread,"A").start();
new Thread(myThread,"B").start();
}
}
// 执行结果
B:3
A:3
A:2
A:1
A:0
程序解读:从这个执行结果可以看出,A:3并且B:3,同一个3出现了两次,明显与逻辑不符,出现了"脏读"。
此时需要给该方法加上synchronized关键字,从而保证一次只会有一个线程进入该方法,保证同步即线程安全。
public synchronized void showNum(){
while (num>0){
num--;
System.out.println(Thread.currentThread().getName()+":"+num);
}
}
// 执行结果
A:4
A:3
A:2
A:1
A:0
程序解读:此时线程A始终拥有该对象的锁,由于线程A和线程B都是在调用对象MyThread,因此A反复进行打印知道num=-1,而当A释放锁后,B获取到锁,此时第一次判断num>0的结果就是false,while循环不会进入,程序执行结束。