synchronized的对象锁和类锁
概念
synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的。
锁机制有如下两种特性:
-
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。
-
可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。
对象锁
synchronized修饰非静态方法时是对象锁,等同于synchronized(this),在同一个对象中是线程安全的。
package com.dwz.concurrency.chapter7; /** * 两个方法锁定的都是this即同一个对象thisLock, * 同时调用的结果是一个执行完再执行下一个 */ public class SynchronizedThis { public static void main(String[] args) { ThisLock thisLock = new ThisLock(); new Thread("T1") { @Override public void run() { thisLock.m1(); } }.start(); new Thread("T2") { @Override public void run() { thisLock.m2(); } }.start(); } } class ThisLock {
public synchronized void m1() { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void m2() { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } }
执行结果:m1和m2先后执行
package com.dwz.concurrency.chapter7; /** * 锁定的是两个不同的对象,没有起到锁的作用,还是多线程执行 */ public class SynchronizedThis2 { public static void main(String[] args) { ThisLock2 thisLock = new ThisLock2(); new Thread("T1") { @Override public void run() { thisLock.m1(); } }.start(); new Thread("T2") { @Override public void run() { thisLock.m2(); } }.start(); } } class ThisLock2 { private final Object LOCK = new Object(); public void m2() { synchronized (LOCK) { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void m1() { synchronized (this) { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
执行结果:m1和m2同时执行
类锁
synchronized修饰静态方法时是类锁,等同于synchronized(类.class),是线程安全的。
package com.dwz.concurrency.chapter7; public class SynchronizedStatic { public synchronized static void m1() { System.out.println("m1" + Thread.currentThread()); try { Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized static void m2() { System.out.println("m2" + Thread.currentThread()); try { Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized static void m3() { System.out.println("m3" + Thread.currentThread()); try { Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } }
测试类
package com.dwz.concurrency.chapter7; public class SynchronizedTest2 { public static void main(String[] args) { new Thread("T1") { @Override public void run() { SynchronizedStatic.m1(); }; }.start(); new Thread("T2") { @Override public void run() { SynchronizedStatic.m2(); }; }.start(); new Thread("T3") { @Override public void run() { SynchronizedStatic.m3(); }; }.start(); } }
执行结果:T1 T2 T3是先后执行的
总结
1、对于静态方法,由于此时对象还未生成,所以只能采用类锁;
2、只要采用类锁,就会拦截所有线程,只能让一个线程访问。
3、对于对象锁(this),如果是同一个实例,就会按顺序访问,但是如果是不同实例,就可以同时访问。
4、如果对象锁跟访问的对象没有关系,那么就会都同时访问。