并发编程学习笔记(九、synchronize)

目录:

  • synchronize作用
  • synchronize使用方式
  • synchronize导致的死锁
  • synchronize特性
  • synchronize原理

synchronize作用

并发场景限制共享资源的访问,使其只有一个线程可以执行某个方法或代码块,实现线程安全

synchronize使用方式

synchronize导致的死锁

Thread1:lock A,waiting for B。

Thread2:lock B,waiting for A。

public class DeadLock {

    /**
     * A锁
     */
    private static String A = "A";

    /**
     * B锁
     */
    private static String B = "B";

    public static void main(String[] args) {
        new DeadLock().deadLock();
    }

    public void deadLock() {
        // 先获取A锁再获取B锁
        Thread t1 = new Thread(() -> {
            synchronized (A) {
                try {
                    // 获取A锁后休眠2s
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    // 获取B锁
                    System.out.println("thread1...");
                }
            }
        });

        // 先获取B锁再获取A锁
        Thread t2 = new Thread(() -> {
            synchronized (B) {
                try {
                    // 获取B锁后休眠2s
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (A) {
                    System.out.println("thread2...");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

synchronize特性

1、原子性:线程互斥的访问同步代码。

2、可见性:保证共享变量的修改能及时可见。

  • 对一个变量unlock时,必须要将其同步到主内存中。
  • 对一个变量lock时,会清空工作内存中此变量的值。
  • 在执行引擎使用此变量前,需要重新从主内存中执行load或assign操作,以初始化变量值。

3、有序性:有效解决重排序问题,即一个unlock操作先行发生与lock操作。

synchronize可以把任何非null的对象作为锁,在Host JVM中锁叫做对象监视器。

synchronize原理

当一个线程访问同步代码块的时候,首先需要获取锁才能执行,当退出或抛出异常时需要释放锁。

那么它是如何来实现这一机制的呢,来看看如下代码:

public class SynchronizedDemo {
    public void method() {
        synchronized (this) {
            System.out.println("Method 1 start");
        }
    }
}

monitorenter:监视器锁(monitor),当monitor被占用时便是锁定状态,执行monitorenter会尝试获取monitor的所有权。过程如下:

  • monitor进入数为0,则该线程进入monitor,进入数为1,则该线程为monitor的所有者。
  • 若该线程已拥有monitor,只是重新进入的话,monitor加1。
  • 如果其它线程占用monitor,则该线程阻塞,直到进入数为0,该线程重新尝试获取monitor的所有权。

monitorexit:执行monitorexit的必须是monitor的拥有者。

  • 执行此操作,monitor的进入数减1,若减1后进入数为0,则线程退出monitor。

———————————————————————————————————————————————————————

通过上述的示例便可以很清楚的了解到synchronize是如何实现的了,通过monitor对象来实现的。

其实wait、notify方法也依赖于monitor对象,这也就是为什么wait、notify方法必须要在synchronize中才能调用的原因了。

posted @ 2020-03-17 22:12  被猪附身的人  阅读(246)  评论(0编辑  收藏  举报