什么是synchronized
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块。
为什么使用synchronized
synchronized的用法
1.同步非静态方法(实例方法)
public class synchronizedTest implements Runnable { static int i =0; public synchronized void increase(){ i++; } @Override public void run(){ for (int j =0 ; j<10000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException { synchronizedTest test = new synchronizedTest(); Thread t1 = new Thread(test); Thread t2 = new Thread(test); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
2.同步静态方法
public class synchronizedTest implements Runnable { static int i =0; public static synchronized void increase(){ i++; } @Override public void run(){ for (int j =0 ; j<10000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new synchronizedTest()); Thread t2 = new Thread(new synchronizedTest()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); }
3.同步代码块
public class synchronizedTest implements Runnable { static synchronizedTest instance=new synchronizedTest(); static int i=0; @Override public void run() { //使用同步代码块对变量i进行同步操作,锁对象为instance synchronized(instance){ for(int j=0;j<10000;j++){ i++; } } } public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
JVM对synchronized的优化
自旋锁:线程频繁的从阻塞到唤醒这段时间,可能会非常耗时,那么自旋锁就会让线程等待一段时间,执行一段无意义的代码(通常是无意义的循环)
锁消除:指有的时候为了保证数据的完整性,我们通常要对这部分代码执行同步控制,但是在某些情况下jvm检测到不存在竞争条件,jvm会将这段同步代码中消除锁
锁粗化:有些时候需要让同步代码的作用范围要尽可能小点,但是有些情况我们需要对多个小部位的加锁替换成整体加锁
轻量级锁:引入轻量级锁的主要目的是在多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。当关闭偏向锁功能或者多个线程竞争偏向锁导致偏向锁升级为轻量级锁,则会尝试获取轻量级锁
偏向锁:为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径。上面提到了轻量级锁的加锁解锁操作是需要依赖多次CAS原子指令的
重量级锁:指没有优化过的同步方法或者同步代码块
Java锁使用的锁其实是在对象头的中锁标识,下面是锁在对象头中的结构
锁的状态