理解Java中的synchronized关键字

学习目标

理解synchronized的含义、明确synchronized关键字修饰普通方法、静态方法和代码块时锁对象的差异。

有如下一个类A

class A {
    public synchronized void a() {
        System.out.println("a"+System.currentTimeMillis());
    }

    public synchronized void b() {
        System.out.println("b"+System.currentTimeMillis());
    }
}

然后创建两个对象

A a1 = new A();
A a2 = new A();

然后在两个线程中并发访问如下代码:

Thread a1.a();
Thread a2.a();

public class Test {
    public static void main(String[] args) {

        A a1 = new A();
        A a2 = new A();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(System.currentTimeMillis());
                a1.a();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(System.currentTimeMillis());
                a2.a();
            }
        }).start();

    }
}

请问二者能否构成线程同步?

如果A的定义是下面这种呢?

class A {
    public static synchronized void a() {
        System.out.println("a"+System.currentTimeMillis());
    }

    public static synchronized void b() {
        System.out.println("b"+System.currentTimeMillis());
    }
}

验证

没有加static的时候结果是这样的:

sync

加了static的时候结果是这样的:

sync1

可以看出,没有static时不能同步,有static时能同步。

Java多线程中的同步机制会对资源进行加锁,保证在同一时间只有一个线程可以操作对应资源,避免多程同时访问相同资源发生冲突。Synchronized是Java中的关键字,它是一种同步锁,可以实现同步机制。

Synchronized主修修饰对象为以下三种:

  1. 修饰普通方法:一个对象中的加锁方法只允许一个线程访问。但要注意这种情况下锁的是访问该方法的实例对象,如果多个线程不同对象访问该方法,则无法保证同步。

  2. 修饰静态方法:由于静态方法是类方法,所以这种情况下锁的是包含这个方法的类,也就是类对象;这样如果多个线程不同对象访问该静态方法,也是可以保证同步的。

  3. 修饰代码块:其中普通代码块,如Synchronized(obj),这里的obj,可以为类中的一个属性、也可以是当前的对象,它的同步效果和修饰普通方法一样;Synchronized方法 (obj.class)静态代码块它的同步效果和修饰静态方法类似。

Synchronized方法控制范围较大,它会同步对象中所有Synchronized方法的代码。

Synchronized代码块控制范围较小,它只会同步代码块中的代码,而位于代码块之外的代码是可以被多个线程访问的。

简单来说 就是 Synchronized代码块更加灵活精确。