多线程问题volatile Synchronise Lock and AtomicReference
以前用到的关于锁和线程安全注意的地方比较少,最近项目出现一些公用内容需保证线程安全所以采用AtomicReference 和concurrentMap,
顺便再梳理了下线程安全的内容:
从性能上来说AtomicReference比synochronizd 和 Lock要好得多。
下面来看下一些实现:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTask implements Runnable { private int lockVariable; private Lock lock; public LockTask() { this.lockVariable = 0; this.lock = new ReentrantLock(); } @Override public void run() { for (int i = 0; i < 1000000000; i++) { lock.lock(); lockVariable = i; lock.unlock(); } } }
public class SecuritySingleton { private static SecuritySingleton securitySingleton; private SecuritySingleton(){}; static synchronized SecuritySingleton getInstance(){ if(securitySingleton==null){ securitySingleton = new SecuritySingleton(); } return securitySingleton; } }
import java.util.concurrent.atomic.AtomicInteger; public class AtomicTask implements Runnable { private final AtomicInteger variableInt; public AtomicTask() { this.variableInt = new AtomicInteger(0); } @Override public void run() { for (int i = 0; i < 1000000000; i++) { variableInt.set(1); } } }
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; public class AtomicService { private final AtomicReference<Map<String, String>> areaMapping = new AtomicReference<>(); private AtomicService() { this.areaMapping.set(new ConcurrentHashMap()); } public void addValue(String key, String value) { areaMapping.get().put(key, value); } public String getValue(String key) { return areaMapping.get().get(key); } }
摘抄自博客:https://www.cnblogs.com/caiba/p/10616615.html
synochronizd和volatile关键字区别:
1. volatile关键字解决的是变量在多个线程之间的可见性;而sychronized关键字解决的是多个线程之间访问共享资源的同步性。
2. volatile只能用于修饰变量,而synchronized可以修饰方法,以及代码块。(volatile是线程同步的轻量级实现,所以volatile性能比synchronized要好,并且随着JDK新版本的发布,sychronized关键字在执行上得到很大的提升,在开发中使用synchronized关键字的比率还是比较大)
3. 多线程访问volatile不会发生阻塞,而sychronized会出现阻塞。
4. volatile能保证变量在多个线程之间的可见性,但不能保证原子性;而sychronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公有内存中的数据做同步。
线程安全包含原子性和可见性两个方面。
对于用volatile修饰的变量,JVM虚拟机只是保证从主内存加载到线程工作内存的值是最新的。
一句话说明volatile的作用:实现变量在多个线程之间的可见性。
synchronized和lock区别
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率(读写锁)。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。