什么是线程安全?
多个线程同一时刻对同一个全局变量(同一份资源)做写操作(读操作不会涉及线程安全)时,如果结果跟我们预期的一样,我们就称之为线程安全,反之,线程不安全。
为了保证线程的安全,最简单的方法就是给相应的方法、对象等加synchronized关键字。
什么是synchronized?
一般说的synchronized用来做多线程同步功能,其实synchronized只是提供多线程互斥,而对象的wait()和notify()方法才提供线程的同步功能。
synchronized是加锁,或者说是加对象锁,其实对象锁只是synchronized在实现锁机制中的一种锁(重量锁,用这种方式互斥线程开销大所以叫重量锁,或者叫对象monitor),而synchronized的锁机制会根据线程竞争情况在运行会有偏向锁、轻量锁、对象锁,自旋锁(或自适应自旋锁)等,总之,synchronized可以认为是一个几种锁过程的封装。
案例
添加进程进ArrayList,存在线程不安全的隐患
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
结果:明明向里面添加了10000个进程,最后ArrayList里只有8050个。
改进方案:添加synchronized关键字,给list上锁。
import java.util.ArrayList;
public class Demo3Synchronous {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
synchronized (list) {
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
结果:ArrayList有10000个进程。