- Class文件加载到同一个ClassLoader空间中是单例的,如果是不同的classloader则不是单例。
- synchronized如果加在静态方法中,则锁住的是类(一般方法中锁住的是this),等同于synchronize(T.class)。
- synchronized锁住的任何对象,看对象头顶的两位01,如果是已经标记过的,则是偏向锁。
- synchronized锁对象底层jvm虚拟机规范没有要求,但是hostpot markword中是用头顶两位用来标记,组合分别是不同锁的类型。
- synchronized(this)表示锁定当前对象,与synchronized方法是等值的,如果静态方法则是锁定的T.class。
- synchronized既保证了原子性又保证了可见性。
- 程序中如果出现异常,则锁会被释放,其他程序会乱入,可能导致数据不一致。
- 我就是厕所所长(一、二)。
- syn(obj) markdown 记录线程id(偏向锁),如果线程过来发现ID是自己的 那就直接用,偏向锁如果线程争用,则会升级为自旋锁(默认旋10次),十次以后还没得到这把锁则升级为重量级锁(-OS), 去操作系统申请资源,变为等待状态则不占用CPU,锁只可以升级,没法降级。(由于java jvm没有规定synchronized如何实现,所以理论上调整jvm也是可以降级锁的),争用大部分是自旋锁,占CPU但是不访问操作系统,所以是用户态,不是内核态,加锁解锁比经过内核态效率要高。
- 执行时间长或线程数量多用系统锁(-OS),时间短(指加锁代码时间短)用自旋锁(但是线程不能太多)。
- 锁定的对象不能是String常量 Integer(特殊处理过) Long等基本数据类型,比如String在常量池中,相同字面量是同一个锁,会出现一个线程死循环,其他线程没法进来,的当使用不可变类对象(final Class)作为对象锁时,使用synchronized同样会有并发问题 比如Integer类,由于不可变特性,作为锁但同步块内部仍然有计算操作,会生成一个新的锁对象(虽然String也是final Class,但它的原因却是字面量常量池),经过反编译之后对于锁定发Integer 变量i, 执行i++操作相当于执行了
i = Integer.valueOf(i.intValue()+1),通过查看Integer的valueOf方法实现可知,其每次都new了一个新的Integer对象,锁变了.。 - Lock与synchronized区别在于,Lock中用的是CAS(很多实现用的是自旋)操作,占用CPU资源,而synchronized自旋(占用CPU时间)之后会进入wait队列,即不占用CPU时间。
- volatile(大厂默认必会的知识点),意思:可变的、易变的,
1、保证线程可见性,不是实时监控。每一个线程有自己的局部内存,当需要使用共享内存中的变量时,会copy一份到自己的局部内存,修改之后会写回共享内存,但是其他需要使用这个变量的线程并不能及时读到自己的内存,这叫线程之间不可见,加了volatile之后可以保证一个线程做出改变之后其他线程能及时感受到。本质是使用了CPU的缓存一致性协议(MESI)
代码演示:
2、禁止指令重排序,跟CPU有关系,现代的CPU为了提高效率会并发执行命令,这种新的架构之上,要求编译器对指令进行重排序,而volatile会禁止指令重排序(JVM级别),
举例子:单例模式的双重检查时,要不要加volatile?要!
public class Mgr06 { private static volatile Mgr06 INSTANCE; //JIT private Mgr06() { } public static Mgr06 getInstance() { if (INSTANCE == null) { //双重检查 synchronized (Mgr06.class) { if(INSTANCE == null) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } INSTANCE = new Mgr06(); } } } return INSTANCE; } public void m() { System.out.println("m"); } public static void main(String[] args) { for(int i=0; i<100; i++) { new Thread(()->{ System.out.println(Mgr06.getInstance().hashCode()); }).start(); } } }
- 锁应尽可能细化,但是如果一段代码块中很多很多锁,则粗化。
- 锁定方法和非锁定方法可以同时执行。
- CAS(compare and set缩写,无锁优化,自旋锁,也叫乐观锁,CPU原语级别的支持所有中间不可以被打断),java.util.concurrent.atomic.AtomicInteger,凡是类加了Atomic的类都是用了CAS优化,线程安全