一个对象对应一把锁,要线程同步需要两者同步为同一对象。在该问题中,synchronized修饰pubulic方法中没有具体的参数默认的锁为this,即是当前实例对象。在创建过程中创建的是两个不同对象,对应两把不同的锁。由于调用时由于用的不是同一个锁,所以不能线程同步。
synchronized修饰的静态方法,能构成线程同步。静态方法加的锁为类对象的锁。由于静态方法具有全局唯一性,调用的时候调用的是同一对象,同一把锁,所以能线程同步。
synchronized修饰代码块有两种锁,一种是对象锁,另外一种是类锁。或者叫实例锁,全局锁。如果采用的是对象锁,需要对象为同一对象才能构成线程同步。如果用的是类锁,而类锁在虚拟机中具有唯一性,自然能构成线程同步。

1. 用在对象

    Lock LOCK = new Lock();

    /**
     * 用在对象
     */
    private void synchronizedInstance() {
        synchronized (LOCK) {
            System.out.println("synchronizedInstance");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

以LOCK 为对象锁了。

    /**
     * 用在this
     */
    private void synchronizedThis() {
        synchronized (this) {
            System.out.println("synchronizedThis");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

当前实例为锁。
对象锁,只有获取当前对象才能进入该方法里面。synchronized methods(){} 与synchronized(this){}之间没有什么区别。

私有锁,在类内部声明一个私有属性如private Object lock,在需要加锁的同步块使用 synchronized(lock)。
使用私有锁可以减小锁的细粒度,减少由锁产生的开销。私有锁其实也是对象锁的一种。
私有锁还可以这样用:用私有锁实现的等待/通知机制。

Object lock = new Object();

// 由等待方线程实现
synchronized (lock) {
    while (条件不满足) {
       lock.wait();
   }
}

// 由通知方线程实现
synchronized (lock) {
   条件发生改变
   lock.notify();
}

2. 用在方法里

    /**
     * 用在普通方法
     */
    private synchronized void synchronizedMethod() {
        System.out.println("synchronizedMethod");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

如果不是单例,同步方法锁将失效。实际上是当前实例作为锁。

    /**
     * 用在静态方法
     */
    private synchronized static void synchronizedStaticMethod() {
        System.out.println("synchronizedStaticMethod");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

静态方法具有全局唯一性,类级别的锁,作为锁线程安全。

3. 用在类里

    /**
     * 用在类
     */
    private void synchronizedClass() {
        synchronized (Sync.class) {
            System.out.println("synchronizedClass");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 用在类
     */
    private void synchronizedGetClass() {
        synchronized (this.getClass()) {
            System.out.println("synchronizedGetClass");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

两个都是类级锁,线程安全。
类锁:使用 synchronized 修饰静态的方法以及 synchronized(class) 同步代码块使用的锁是类锁。
对象锁:使用 synchronized 修饰非静态的方法以及 synchronized(this) 同步代码块使用的锁是对象锁。

类锁和对对象锁不相互阻塞,相同的类锁或相同的实例锁相互阻塞。方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。保证了同一时刻只有一个线程可执行,从而有效的避免了类成员变量的访问冲突。

打赏 赞(0)
微信
支付宝
微信二维码图片

微信扫描二维码打赏

支付宝二维码图片

支付宝扫描二维码打赏

分类: Java

0 条评论

发表评论

电子邮件地址不会被公开。