volatile:
- 保证可见性
- 不保证原子性
- 禁止指令重排序
为什么不保证原子性?
因为当一个两个线程一起写入工作内存的时候,一个线程挂起,一个线程写入,当写入的线程通知的时候,另一个线程还没有来的及收到通知,就写入工作内存中,所以就没有原子性了
单例模式要加volatile来禁止指令重排
可以用AtomicInteger来替代
AtomicInteger的底层是CAS
JMM:
- 可见性
- 原子性
- 有序性
CAS:
- unsafe :是CPU的一条并发原语,用内存地址偏移量来修改值,直到比较成功才更新成功
- 自旋锁
缺点: - 会一直自旋,循环开销大,给cpu导致很大的开销
- 只能对一个共享变量进行原子性操作
- ABA问题:用修改版本号来避免AtomicStampedReference
ArrayList:
线程不安全,解决:
- vector 加了synchronize的ArrayList
- Collections.synchronizedList(new ArrayList<>());
- new CopyOnWriteArrayList<>();用了volatile和写时复制
CopyOnWriteArraySet用的也是CopyOnWriteArrayList
原因:一个同学在修改的时候,另一个同学过来修改,导致并发异常
HashSet底层是HashMap
他的value是present的一个Object类
ConcurrentHashMap只会对一段数据上锁,而不会对整个map上锁
公平锁和非公平锁
synchronize是非公平锁
ReentrantLock可以选择,默认是非公平锁
这两个锁都是可重入锁,可以避免死锁
自旋就是while循环加CAS,但是如果自旋锁太重了,可能会拖慢系统,因为等待的线程一直在自旋。
public class Main {
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void myLock(){
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+" is comming");
while(!atomicReference.compareAndSet(null, thread)){}
}
public void unLock(){
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread, null);
System.out.println(Thread.currentThread().getName()+"It's time to unlock");
}
public static void main(String[] args) {
Main main = new Main();
new Thread(()->{
main.myLock();
try{
TimeUnit.SECONDS.sleep(5);
}catch(Exception e){
e.printStackTrace();
}
main.unLock();
}).start();
try{
TimeUnit.SECONDS.sleep(1);
}catch(Exception e){
e.printStackTrace();
}
new Thread(()->{
main.myLock();
try{
TimeUnit.SECONDS.sleep(1);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("------------------");
main.unLock();
}).start();
}
}