一、为什么会发生多线程并发问题?
并发问题的根本原因是操作了共享资源,比如一个统计网站访问量的功能,每个用户进来就需要对访问量加1,如果做不好,那么就会导致统计的数字不准确
二、在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题。
三、具体的解决方案有哪些?
1、ThreadLocal:ThreadLocal本质上是每个线程有自己的一个副本,每个线程的副本是互不影响,没有任何关系的。
2、CAS原子类:CAS的意思是Compare And Swap,就是比较并替换的意思,CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B,只有当内存地址V所对应的值和旧的预期值A相等的时候,才会将内存地址V对应的值更新为新的值B。Java中,Atomic系列使用的是一种无锁化的CAS操作,是基于乐观锁的,它的并发性能比较高,可以多个线程同时执行,并且保证不会出现线程安全问题。
3、volatile关键字
volatile关键字可以保证可见性和禁止指令重排序,它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;它会强制将对缓存的修改操作立即写入主存;如果是写操作,它会导致其他CPU中对应的缓存行无效。
volatile使用的场景:从上面看,其实volatile关键字使用的场景比较少,比如像状态开关,双重检查。
4、synchronized关键字
4.1、synchronized的三种使用方法:
修饰实例方法、修饰静态方法、修饰代码块
5、Lock相关类
Lock和synchronized有以下几点不同:
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。