synchronized

作者: 刘一一同学 | 来源:发表于2019-07-06 23:52 被阅读0次

1. 概述

在Java早期版本,synchronized属于重量级锁,效率低下,因为使用监视器锁(monitor)依赖于底层操作系统的互斥锁(Mutex Lock)来实现,而Java的线程是映射到操作系统的原生线程之上的,如果挂起或者唤醒一个线程,都需要操作系统从用户态切换到内核态,这个状态之间的切换需要耗费较高的时间成本,这也是为什么早期的synchronized效率低的原因。synchronized使对象在同一时刻只能被一个线程访问,因此能够解决多线程之间数据同步问题。

2. 使用方式

  1. 同步普通方法:对当前对象加锁。
  2. 同步静态方法:对当前Class对象加锁。
  3. 同步代码块:对当前代码块加锁。

3. 实现原理

synchronized同步语句块的实现使用JVM的是monitorentermonitorexit指令,其中monitorenter指令指向同步代码块的开始位置, monitorexit指令指向同步代码块的结束位置。当执行monitorenter指令时,线程试图获取锁,也就是获取monitor的持有权。每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加一,释放锁后就会将计数器减一。

monitor对象存在于每个对象的对象头中,synchronized便是通过这种方式获取锁的,也就是为什么Java中任意对象可以作为锁的原因。

4. synchronized和ReentrantLock的区别

  1. 两者都是可重入锁
    可重入锁,已经获得锁的线程可以再次获取自己的内部锁。比如一个线程获得了某个对象锁,此时这个对象锁还没有释放,当这个线程再次想要获取这个对象锁的时候还是可以获取的,如果锁不可重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。

  2. 两者依赖不同
    synchronized依赖于JVM,而RennTrantLock依赖于API。JDK1.6为synchronized关键字进行了很多优化,但是这些优化都是在虚拟机层面实现的,并没有直接暴露给我们。RenntrantLock是JDK层面实现,也就是API层面,需要lock()unlock()方法配合try/finally语句块来完成。

5. 使用示例

public class SynchronizedDemo {

    //声明一个实例变量
    private String name = "test";

    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {
            new Thread("同步普通方法" + i) {
                @Override
                public void run() {
                    new SynchronizedDemo().demo1();
                }
            }.start();
            new Thread("同步静态方法" + i) {
                @Override
                public void run() {
                    SynchronizedDemo.demo2();
                }
            }.start();
            new Thread("同步当前对象" + i) {
                @Override
                public void run() {
                    new SynchronizedDemo().demo3();
                }
            }.start();
            new Thread("同步指定对象" + i) {
                @Override
                public void run() {
                    new SynchronizedDemo().demo4();
                }
            }.start();
            new Thread("同步class类对象" + i) {
                @Override
                public void run() {
                    new SynchronizedDemo().demo5();
                }
            }.start();
        }
    }

    /**
     * 同步实列方法
     */
    public synchronized void demo1() {
        try {
            System.out.println(Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 同步静态方法
     */
    public synchronized static void demo2() {
        try {
            System.out.println(Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 同步当前对象
     */
    public void demo3() {
        synchronized (this) {
            try {
                System.out.println(Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 同步指定对象
     */
    public void demo4() {
        synchronized (name) {
            try {
                System.out.println(Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 同步class类对象
     */
    public void demo5() {
        synchronized (SynchronizedDemo.class) {
            try {
                System.out.println(Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

相关文章

网友评论

    本文标题:synchronized

    本文链接:https://www.haomeiwen.com/subject/zumecctx.html