目前我理解的synchronized锁分为对象锁和类锁
对象锁
例如
class C { public synchronized void aa() { System.out.println("aa method"); try { Thread.sleep(10000); } catch (final InterruptedException e) { e.printStackTrace(); } } public synchronized void bb() { System.out.print("bb method"); }
}
这就是 对象锁 当同一个对象 在不同线程调用方法的时候 会串行的访问 例如 线程1访问完aa 线程b才能访问 (这是一种情况,)第二种线程1在执行aa 线程2也不能执行bb() 因为对象锁被线程1持有。 如果在两个线程中的对象不是同一个实例那么无论如何都不会引起阻塞。因为他们是持有了不同的对象锁。
下面是例子:
public class ThreadTest { private static final C c = new C(); public static void main(final String[] args) { new Thread(new Runnable() { @Override public void run() { c.aa(); } }).start(); new Thread(new Runnable() { @Override public void run() { c.bb(); } }).start(); } }class C { public synchronized void aa() { System.out.println("aa method"); try { Thread.sleep(10000); } catch (final InterruptedException e) { e.printStackTrace(); } } public synchronized void bb() { System.out.print("bb method"); }
}
两个线程都持有一个对象c,那么无论谁先执行,当一个线程执行的时候,另一个线程注定不能进入同一个同步方法,因为对象锁被占有了。这里可以把锁看成一种资源。
下面是类锁,首先说说什么样的是类锁,我理解的是 只要是像synchronized(XXX.class) 或者是静态的同步方法,那么线程进入到这些区域的时候就会先获得类锁。类锁也是一种稀缺的资源,
当一个线程获得了一个类锁后,那么其他线程就不能够进入到(需要这把类锁才能进入的方法和同步块中)例如两个线程,分别叫线程1和线程2 ,当线程1调用一个静态同步方法的时候,另一个线程2不能调用这个方法,或者这个类的其他静态同步方法。但是非静态的同步方法是不会被阻塞的,因为 两者的锁不相同,一个是类锁,一个是对象锁。
下面是代码示例:
public class ThreadTest1 { public static void main(final String[] args) { final ThreadA threadA = new ThreadA(); threadA.setName("A"); threadA.start(); final ThreadB threadB = new ThreadB(); threadB.setName("B"); threadB.start(); } }class Service { public void printA() { synchronized (Service.class) { System.out.println("线程" + Thread.currentThread().getName() + "进入printA"); System.out.println(Thread.currentThread().getName()); try { Thread.sleep(10000); } catch (final InterruptedException e) { e.printStackTrace(); } System.out.println("线程" + Thread.currentThread().getName() + "离开printA"); } } public void printB() { synchronized (Service.class) { System.out.println("线程" + Thread.currentThread().getName() + "进入printB"); System.out.println(Thread.currentThread().getName()); System.out.println("线程" + Thread.currentThread().getName() + "离开printB"); } } }class ThreadA extends Thread { @Override public void run() { new Service().printA(); } }class ThreadB extends Thread { @Override public void run() { new Service().printB(); }
}
当线程1进入到printA()当中的时候,会陷入睡眠10秒,这时候会发现线程2无法执行printB()方法,(这是再线程1先抢到了类锁的情况下),因为线程2要想调用PrintB()它要先获得类锁,而类锁被线程1占用。这样线程1就把线程2阻塞了。