java锁
1.Synchronized
包括对象锁,类锁
对象锁:
作用于一个普通类的代码块,那么当前加锁的级别就是实例对象,当多个线程并发访问该对象的同步方法、同步代码块时,会进行同步。
类锁:
修饰类静态方法时,那么当前加锁的级别就是类,当多个线程并发访问该类(所有实例对象)的同步方法以及同步代码块时,会进行同步。
同步代码块
修饰代码块时,那么当前加锁的级别就是synchronized(X)中配置的x对象实例,当多个线程并发访问该对象的同步方法、同步代码块以及当前的代码块时,会进行同步。
使用同步代码块时要注意的是不要使用String类型对象,因为String常量池的存在,所以很容易导致出问题。
通过jvm的参数设置可以启用轻量级锁,轻量级锁的对象的对象头信息的markword字段来设置,
当一个轻量级锁被锁定时不会进入内核态的阻塞,而是通过修改对象头信息进入自旋状态(即java级的一个循环),当有别的线程竞争这个锁时会触发重量级锁,
重量级锁就是普通的锁,会由用户态切换到内核态,然后进入阻塞状态。因为向内核态的切换比较耗资源自旋锁减少了这种开销,但是自旋操作比较耗费java资源,如果出现线程间竞争就会大量浪费资源, 轻量级锁适用于线程内加锁解锁操作。
偏向锁是比轻量级锁更轻量的锁,适用于一个线程内频繁的加锁解锁。
自适应锁是自旋锁的一种改进,它在进行一定次数的自旋以后会进入内核级阻塞。
2、volatile
可见性
我们知道volatile可以看做是一种synchronized的轻量级锁,他能够保证并发时,被它修饰的共享变量的可见性,那么他是如何实现可见性的呢?
我们从jmm的角度来看一下,每个线程拥有自己的工作内存,实际上线程所修改的共享变量是从主内存中拷贝的副本,当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
实现原理
被volatile修饰的共享变量在进行写操作的时候:
1、将当前处理器缓存行的数据写回到系统内存。
2、这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效