并发编程(十一)Synchronized 的特性

65 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

1.Synchronized 的特性

1. 有序性 (读读、读写、写读、写写 互斥)

这里读是指读线程,写是指写线程,这里指的是任何两个线程都是互斥的,都存在竞争锁,不可同时获得锁。后续我们会详细讲ObjectMonitor。

2. 可见性 (可见性是指多个线程访问⼀个资源时,该资源的状态、值信息等对于其他线程都是可见的。

synchronized和volatile都具有可见性,其中synchronized对⼀个类或对象加锁时,⼀个线程如果要访问该类或对象必须先获得它的锁,⽽这个锁的状态对于其他任何线程都是可见的,并且在释放锁之前会将对变量的修改刷新到共享内存当中,保证资源变量的可见性。)

4. 原子性 (本质上是线程互斥保证的原子性)

因为加上synchronize锁后,里面的内容只有获得锁后才能执行,所以要么获得锁执行,要么没获得锁在竞争。

4. 可重入性 (代码示例 ThreadReIn.java)

这里我们看一下代码示例:

public class ThreadReIn implements Runnable {
    static ThreadReIn instance = new ThreadReIn();
    static int i = 0;
    static int j = 0;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("i:"+i);
        System.out.println("j:"+j);
    }
    @Override
    public void run() {
        System.out.println(this);
        for (int j = 0; j < 1000000; j++) {
            // this,当前实例对象锁
            synchronized (this) {
                i++;
                increase();// synchronized的可重入性
            }
        }
    }
    public synchronized void increase() {
        j++;
    }
}

执行效果如下:

image.png

为什么这个例子可以说明是可重入性呢?

首先我们可以看到这个例子中2个线程中的this都是指的instance这个对象,所以一个线程的第一次加锁指的是同步代码块synchronized (this) 加锁,第二层加锁指的是increase()方法,这个方法命名中有synchronize关键字,而且还是非静态的,所以加的锁也是this。

而我们可以看到最后的结果i、j也都是2000000,并没有产生并发问题。

今天这章节就到这里,下面章节将介绍synchronize的对象头!