一、什么叫线程安全
如果在多线程的环境下代码运行的结果是符合预期的,就说明这个线程是安全的。
二、线程为什么会不安全
如果多个线程对共享变量进行修改就会发生线程不安全。
- 原子性
没有保障原子性会导致线程不安全,由于线程的抢占式调度原则,如果一个线程在对变量操作,中途其他线程插入,结果就有可能是错误的。 - 可见性(一个线程对共享变量的修改能及时被其他线程看到)
由于每个线程有自己的工作内存,这些内存中的内容相当于同一个共享变量的“副本”。此时修改线程1的工作内存的值,线程2的工作内存不一定会及时变化,从而导致线程不安全。
三、如何解决线程不安全的问题
答案:加锁
-
synchronized关键字------监视器锁
synchronized会起到互斥效果,某个线程执行到某个对象的synchronized中时,其他线程如果也执行到这就会阻塞等待。特性:
进入synchronized修饰的代码块:加锁;
退出synchronized修饰的代码块:解锁;刷新内存的工作机制:
synchronized的工作过程:1.获得互斥锁-》2.从主内存拷贝最新变量副本到工作内存-》3.执行代码-》4.更改后的共享变量刷新到主内存-》5.释放互斥锁;可重入性:
synchronized对同一条线程是可重入的,不会把自己锁死。用法:
public class SynchronizedUse {
//1.修饰普通方法
public synchronized void func(){
}
//2.修饰静态方法
public synchronized static void func2(){
}
//3.修饰代码块:需明确指定对象
public void func3(){
synchronized (this){
//代码。。。
}
}
}
2.volatile关键字
volatile修饰的变量能够保证“内存可见性”,但不保证原子性。
当代码写入volatile修饰的变量时:
- 改变线程工作内存中volatile变量副本的值;
- 将改变后的值刷新到主内存;
当代码读取volatile修饰的变量时:
- 从主内存读取最新值到线程的工作内存中;
- 从工作内存中读取volatile变量的副本。