Java并发编程(四) —— synchronized

一、概念

利用锁机制实现线程同步,synchronized关键字的底层交由了JVM通过C++来实现

Java中的锁有两大特性:

  • 互斥性
    • 同一时间,只允许一个线程持有某个对象锁。
  • 可见性
    • 锁释放前,线程对变量的修改,后面获得锁的线程可见。

可见性

JMM关于synchronized的两条规定:

  1. 线程解锁前,必须把共享变量的最新值刷新到主内存中

  2. 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值(注意:加锁与解锁需要是同一把锁)

通过以上两点,可以看到synchronized能够实现可见性。

二、用法

synchronized修饰位置与锁的关系

  • 同步方法 —— 对象锁,当前实例对象
  • 静态同步方法 —— 类对象锁,当前对象的Class对象
  • 同步方法块 —— 对象锁,synchonized括号里配置的对象

public class SynchronizedDemo {

    private static int m = 0;

    private Object obj = new Object();

    /**
     * 修饰非静态方法
     */
    public synchronized void m1() {
        sleep(2);
        m++;
    }

    /**
     * 修饰静态方法
     */
    public synchronized static void m2() {
        sleep(2);
        m++;
    }

    /**
     * 同步代码块,对对象加锁
     */
    public synchronized void m3() {
        synchronized (this) {
            sleep(2);
            m++;
        }
    }

    public synchronized void m4() {
        synchronized (obj) {
            sleep(2);
            m++;
        }
    }

    /**
     * 同步代码块,对类加锁
     */
    public synchronized void m5() {
        synchronized (SynchronizedDemo.class) {
            sleep(2);
            m++;
        }
    }

    public static void sleep(int second) {

        try {
            Thread.sleep(second * 1_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}


三、面试问题

同一个对象在A、B两个线程中分别访问该对象的两个同步方法writer和reader,是否会产生互斥?


class LockDemo{
	
	int a = 0;
	
	public synchronized void writer(){
		sleep(10);
		a++;
	}
	
	public synchronized void reader(){
		int i = a;
	}
	
	public static void main(String[] args) {
	
        Test test = new Test();
        new Thread(() -> {
            test.writer();
        }).start();
        
        sleep(1);
        
        new Thread(() -> {
            test.reader();
        }).start();

    }

}


答案:会。因为synchronized修饰的是方法,锁是对象锁,默认当前的对象作为锁的对象。只有当A释放锁之后,B才会获得对象的锁。

(1)如果是换成是不同对象呢?

不会互斥,因为锁的是对象,而不是方法

(2)如果writer、reader方法加上static修饰,两个线程中,类直接调用两个方法呢?

会互斥,因为锁的是Class对象。

(3)如果writer方法用static修饰,reader方法不用呢?

不会互斥。因为一个是对象锁,一个是Class对象锁,锁的类型不同。

posted @ 2019-05-15 23:06  清泉白石  阅读(245)  评论(0编辑  收藏  举报