一、锁
-
定义
锁是在不同线程竞争资源的情况下用来分配不同线程执行方式的同步控制工具,只有线程获取到锁之后才能访问同步代码,否则需等待其他线程使用结束后释放锁。
-
synchronized
隐式锁,通常和wait(),notify(),notifyAll()一块使用。
- wait:释放占有的对象锁,释放CPU,进入等待队列只能通过notify/notifyAll继续该线程。
- sleep:释放CPU,但是不释放占有的对象锁,可以在sleep结束后自动继续该线程。
- notify:唤醒等待队列中的一个线程,使其获得锁进行访问。
- notifyAll:唤醒等待队列中等待该对象锁的全部线程,让其竞争去获得锁。
-
lock
显示锁,拥有synchronize相同的语义,但是添加一些其他特性,如中断锁等候和定时锁等候。可以使用lock代替synchronize,但必须手动加锁和释放锁。通过lock()手动加锁,通过unlock()方法手动释放锁,unlock()方法需要放到finally里保证锁能释放。
-
synchronized与lock的区别.
synchronized lock 性能 稍差【竞争激烈时】/差不多【竞争不激烈】 好【竞争激烈时】/差不多【竞争不激烈】 用法 代码块上,方法上 通过代码实现,需要手动上锁与释放,提供了多样化的同步,如公平锁、有时间限制的同步、可以被中断的同步 原理 在JVM级别实现,会在生成的字节码中加上monitorenter和monitorexit,任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他将处于锁定状态。monitor是JVM的一个同步工具,synchronized还通过内存指令屏障来保证共享变量的可见性。 使用AQS在代码级别实现,通过Unsafe.park调用操作系统内核进行阻塞。 功能 非公平锁、要么随机唤醒一个线程要么唤醒全部线程 ReentrantLock:可指定公平锁/非公平锁。提供Condition(条件)类,可实现分组唤醒。提供中断等待机制【lockInterruptibly()】 使用总结:
写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。
-
volatile
- 在主内存和工作内存交互时,直接与主内存产生交互【不通过缓存】,进行读写操作,保证数据的内存可见性【实时刷新】;
- 禁止 JVM 进行的指令重排序。
-
ThreadLocal
使用
ThreadLocal<UserInfo> userInfo = new ThreadLocal<UserInfo>()
的方式,让每个线程内部都会维护一个ThreadLocalMap,里边包含若干了 Entry(K-V 键值对),每次存取都会先获取到当前线程ID,然后得到该线程对象中的Map,然后与Map交互。