synchronized的使用
修饰实例方法
修饰静态方法
修饰代码块
总结
Synchronzied的底层原理
对象头和内置锁(ObjectMonitor)
synchronzied的底层原理
synchronized的优化
偏向锁
轻量级锁
轻量级锁膨胀
重量级锁
自旋
编译期间锁优化
总结
参考资料
synchronized的使用synchronized关键字是Java中解决并发问题的一种常用方法,也是最简单的一种方法,其作用有三个:(1)互斥性:确保线程互斥的访问同步代码(2)可见性:保证共享变量的修改能够及时可见(3)有序性:有效解决重排序问题,其用法也有三个:
修饰实例方法
修饰静态方法
修饰代码块
修饰实例方法 public class Thread1 implements Runnable{ //共享资源(临界资源) static int i=0; //如果没有synchronized关键字,输出小于20000 public synchronized void increase(){ i++; } public void run() { for(int j=0;j<10000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException { Thread1 t=new Thread1(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); t1.join();//主线程等待t1执行完毕 t2.join();//主线程等待t2执行完毕 System.out.println(i); } /** * 输出结果: * 20000 */ } 修饰静态方法 public class Thread1 { //共享资源(临界资源) static int i = 0; //如果没有synchronized关键字,输出小于20000 public static synchronized void increase() { i++; } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runnable() { public void run() { for (int j = 0; j < 10000; j++) { increase(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 10000; j++) { increase(); } } }); t1.start(); t2.start(); t1.join();//主线程等待t1执行完毕 t2.join();//主线程等待t2执行完毕 System.out.println(i); } /** * 输出结果: * 20000 */ } 修饰代码块 public class Thread1 implements Runnable{ //共享资源(临界资源) static int i=0; @Override public void run() { for(int j=0;j<10000;j++){ //获得了String的类锁 synchronized (String.class){ i++;} } } public static void main(String[] args) throws InterruptedException { Thread1 t=new Thread1(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } /** * 输出结果: * 20000 */ } 总结synchronized修饰的实例方法,多线程并发访问时,只能有一个线程进入,获得对象内置锁,其他线程阻塞等待,但在此期间线程仍然可以访问其他方法。
synchronized修饰的静态方法,多线程并发访问时,只能有一个线程进入,获得类锁,其他线程阻塞等待,但在此期间线程仍然可以访问其他方法。
synchronized修饰的代码块,多线程并发访问时,只能有一个线程进入,根据括号中的对象或者是类,获得相应的对象内置锁或者是类锁
每个类都有一个类锁,类的每个对象也有一个内置锁,它们是互不干扰的,也就是说一个线程可以同时获得类锁和该类实例化对象的内置锁,当线程访问非synchronzied修饰的方法时,并不需要获得锁,因此不会产生阻塞。
Synchronzied的底层原理 对象头和内置锁(ObjectMonitor)根据jvm的分区,对象分配在堆内存中,可以用下图表示: