多线程的概念我就不说了
第一个问题:多线程为什么需要同步?
这个可以参考我的另一篇java内存模型,当多个线程同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,如果没有同步就会导致变量值或对象状态出现混乱从而导致程序异常。
第二个问题:如何实现同步?
方式1:使用Synchronized关键字修饰方法
当用此关键字修饰方法时,内置锁会保护整个方法,在调用这个方法前,需要得到这个锁,否则处于阻塞状态。如果Synchronized修饰的是静态方法,锁住的就是整个类。
方法2:使用Synchronized关键字修饰语句块
通常如果没有必要同步整个方法,同步关键代码就行。
方法3:使用volatile修饰域变量
volatile变量能保证对变量的修改能立即同步到主内存,线程每次访问volatile修饰的变量都是从主内存中访问,所以所有线程访问到的变量值都是一样的。即volatile保证了可见性。不能保证原子性所以不是线程安全的。
方法4:使用ReentrantLock重入锁
方法5:使用ThreadLocal实现同步(空间换时间)
ThreadLocal为每个使用该变量的线程提供独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
为每个使用该变量的线程提供独立的变量副本的方法:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键位线程对象,值对应线程的变量副本。