synchronized

synchronized的两种用法

  1. 对象锁

包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)

  1. 类锁

指synchronized修饰 static方法 或指定锁对象为 Class对象

对象锁

同步代码块

使用 this 锁定代码块

public class SynchronizedObjectCodeBlock2 implements Runnable {

    static SynchronizedObjectCodeBlock2 codeBlock2 = new SynchronizedObjectCodeBlock2();

    @Override
    public void run() {

        synchronized (this) {
            System.out.println("我是lock2, 我叫" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ", lock2 部分执行结束");
        }

    }

    public static void main(String[] args) {

        Thread thread1 = new Thread(codeBlock2);
        Thread thread2 = new Thread(codeBlock2);

        thread1.start();
        thread2.start();

        while (thread1.isAlive() || thread2.isAlive()) {

        }

        System.out.println("finished");

    }
}

最终运行结果

我是lock2, 我叫Thread-0
Thread-0, lock2 部分执行结束
我是lock2, 我叫Thread-1
Thread-1, lock2 部分执行结束
finished

使用 自定义锁对象

public class SynchronizedObjectCodeBlock2 implements Runnable {

    static SynchronizedObjectCodeBlock2 codeBlock2 = new SynchronizedObjectCodeBlock2();

    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    @Override
    public void run() {

        synchronized (lock1) {
            System.out.println("我是lock1, 我叫" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ", lock1 部分执行结束");
        }

        synchronized (lock2) {
            System.out.println("我是lock2, 我叫" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ", lock2 部分执行结束");
        }

    }

    public static void main(String[] args) {

        Thread thread1 = new Thread(codeBlock2);
        Thread thread2 = new Thread(codeBlock2);

        thread1.start();
        thread2.start();

        while (thread1.isAlive() || thread2.isAlive()) {

        }

        System.out.println("finished");

    }
}

运行结果,可以看出来加粗部分, thread-0和thread-1同时执行和同时结束,因为两个线程使用的不是同一把锁。

我是lock1, 我叫Thread-0
Thread-0, lock1 部分执行结束
我是lock2, 我叫Thread-0
我是lock1, 我叫Thread-1

Thread-1, lock1 部分执行结束
Thread-0, lock2 部分执行结束

我是lock2, 我叫Thread-1
Thread-1, lock2 部分执行结束
finished

方法锁

代码展示

public class SynchronizedObjectMethod3 implements Runnable {

    public static void main(String[] args) {

        SynchronizedObjectMethod3 objectMethod3 = new SynchronizedObjectMethod3();

        Thread thread1 = new Thread(objectMethod3);
        Thread thread2 = new Thread(objectMethod3);

        thread1.start();
        thread2.start();
    }

    @Override
    public void run() {
        method();
    }

    public synchronized void method() {
        System.out.println("对象锁的方法修饰符形式, threadName=" + Thread.currentThread().getName());
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "运行结束");
    }
}

运行结果:

使用synchronized修饰一个成员方法, 该方法会根据实例依次执行.
对象锁的方法修饰符形式, threadName=Thread-0
Thread-0运行结束
对象锁的方法修饰符形式, threadName=Thread-1
Thread-1运行结束

类锁

概念:

  1. 只有一个Class对象: Java类可能会有很多个实例对象, 但是只有一个Class对象
  2. 本质: 所谓的类锁, 实质上是Class对象的锁而已
  3. 用法和效果: 类锁只能在同一时刻被同一对象拥有

同步一个全局方法

代码展示

public class SynchronizedClassStatic4 implements Runnable {

    static SynchronizedClassStatic4 instance1 = new SynchronizedClassStatic4();
    static SynchronizedClassStatic4 instance2 = new SynchronizedClassStatic4();

    @Override
    public void run() {
        method();
    }

    public static synchronized void method() {
        System.out.println("我是类锁的第一种形式: static形式, 我叫 " + Thread.currentThread().getName());
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "运行结束");
    }

    public static void main(String[] args) {

        Thread thread1 = new Thread(instance1);
        Thread thread2 = new Thread(instance2);

        thread1.start();
        thread2.start();

        while (thread1.isAlive() || thread2.isAlive()) {

        }

        System.out.println("finished");

    }
}

运行结果:

使用synchronized修饰一个全局方法(static修饰), synchronized默认使用类作为锁对象
我是类锁的第一种形式: static形式, 我叫 Thread-0
Thread-0运行结束
我是类锁的第一种形式: static形式, 我叫 Thread-1
Thread-1运行结束
finished

类锁同步一个代码块

代码展示

public class SynchronizedClassClass5 implements Runnable {

    static SynchronizedClassClass5 instance1 = new SynchronizedClassClass5();
    static SynchronizedClassClass5 instance2 = new SynchronizedClassClass5();

    @Override
    public void run() {
        method();
    }

    private void method() {
        synchronized(SynchronizedClassClass5.class) {
            System.out.println("类锁的第二种表现形式, synchronized(*.class)的形式, 这是" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "运行结束");
        }
    }

    public static void main(String[] args) {

        Thread thread1 = new Thread(instance1);
        Thread thread2 = new Thread(instance2);

        thread1.start();
        thread2.start();

        while (thread1.isAlive() || thread2.isAlive()) {

        }

        System.out.println("finished");

    }


}

运行结果:

尽管Thread使用的不同的instance对象, 但是使用了*.class类锁之后, 代码也会按照期望值运行.
类锁的第二种表现形式, synchronized(.class)的形式, 这是Thread-0
Thread-0运行结束
类锁的第二种表现形式, synchronized(
.class)的形式, 这是Thread-1
Thread-1运行结束
finished