在多线程编程中 synchronized 一直是元老级的角色, 很多人称呼它为重量级锁. Java6 之后为了减少获得锁和释放锁带来的性能消耗引入了偏向锁和轻量级锁, 对 synchronized 进行了各种优化, 它变得不那么重了.
synchronized 实现同步的基础是: Java 中的每一个对象都可以作为锁.
具体见以下四种形式, 其中 1,2 属于同一类, 都是对一个普通的对象加锁, 3,4 属于同一类, 都是对类的 class 对象加锁.
对于普通同步方法, 锁是当前实例对象, 即 this.
对于同步方法块, 锁是 synchronized 括号里配置的对象, 这个对象也可以是 this.
对于静态同步方法, 锁是当前类的 class 对象.
对于静态同步方法块 (synchronized 括号里是类的 class 对象), 和第三种情况一样, 锁是当前类的 class 对象.
当一个线程试图访问同步代码块时, 它首先必须得到锁, 退出或抛出异常时就会释放锁.
下面对第四种情况做一个演示:
- class ServiceObj{
- public void doService() {
- synchronized (ServiceObj.class) {
- System.out.println(Thread.currentThread().getName()+"的业务方法开始");
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName()+"的业务方法结束");
- }
- }
- }
- class MyThread extends Thread{
- private ServiceObj serviceObj;
- public MyThread(ServiceObj serviceObj) {
- super();
- this.serviceObj=serviceObj;
- }
- @Override
- public void run() {
- serviceObj.doService();
- }
- }
- public class SynchTest {
- public static void main(String[] args) {
- ServiceObj serviceObj0 = new ServiceObj();
- MyThread myThread0 = new MyThread(serviceObj0);
- myThread0.start();
- ServiceObj serviceObj1=new ServiceObj();
- MyThread myThread1=new MyThread(serviceObj1);
- myThread1.start();
- }
- }
输出结果如下:
Thread-0 的业务方法开始
Thread-0 的业务方法结束
Thread-1 的业务方法开始
Thread-1 的业务方法结束
可以看到两个线程保持同步.
但如果我们把 synchronized 括号里的内容改一下, 变为情况二:
synchronized (this)
输出结果就不同步了, 如下:
Thread-0 的业务方法开始
Thread-1 的业务方法开始
Thread-1 的业务方法结束
Thread-0 的业务方法结束
因为一个是对类加锁, 另一个是对对象加锁.
来源: http://www.bubuko.com/infodetail-2601939.html