Skip to content

同步互斥

Java 对于共享资源的互斥访问提供了在 Jvm 层面基于 synchronized 实现, JDK 层面基于 ReentrantLock 来实现

synchronized

同步代码块

只作用同一个对象,如果调用不同对象的同步代码块,就不会进行同步

java
public class SynchronizedObjectDemo {

    /*
    同步一个代码块:作用同一个对象
     */
    public void executor() {
        synchronized (this) {
            for (int i =0; i < 10; i++) {
                System.out.print(i + " ");
            }
        }
    }


    public static void test1() throws InterruptedException {
        SynchronizedObjectDemo demo = new SynchronizedObjectDemo();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(demo::executor);
        executorService.execute(demo::executor);
        Thread.sleep(2);
        executorService.shutdown();
    }

    public static void test2() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        SynchronizedObjectDemo demo1 = new SynchronizedObjectDemo();
        SynchronizedObjectDemo demo2 = new SynchronizedObjectDemo();
        executorService.execute(demo1::executor);
        executorService.execute(demo2::executor);
        Thread.sleep(2);
        executorService.shutdown();
    }

    public static void main(String[] args) throws InterruptedException{
        test1();
        test2();
    }
}

test1 方法执行结果如下:

由于调用同一个对象的同步代码块,因此这两个线程回进行同步,当一个线程进入同步语句,另外一个对象就必须等待

text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

text2 方法执行结果如下:

两个线程调用了不同对象的同步代码块,因此两个线程不需要同步,从运行结果可以看到交叉执行

text
0 1 0 2 3 1 4 5 2 3 6 4 7 8 5 9 6 7 8 9

同步一个方法

java
public class SynchronizedMethodDemo {

    public synchronized void executor() {
        for (int i =0; i< 10; i++) {
            System.out.print(i +" ");
        }
    }

    public static void test1() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        SynchronizedMethodDemo demo = new SynchronizedMethodDemo();
        executorService.execute(demo::executor);
        executorService.execute(demo::executor);
        Thread.sleep(2000);
        executorService.shutdown();
    }

    public static void test2() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        SynchronizedMethodDemo demo = new SynchronizedMethodDemo();
        SynchronizedMethodDemo demo1 = new SynchronizedMethodDemo();
        executorService.execute(demo::executor);
        executorService.execute(demo1::executor);
        Thread.sleep(2000);
        executorService.shutdown();
    }

    public static void main(String[] args) throws InterruptedException {
        test1();
        test2();
    }
}

test1 方法执行结果如下:

text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

text2 方法执行结果如下:

text
0 1 0 2 3 1 4 5 2 3 6 4 7 8 5 9 6 7 8 9

同步一个类

java
public class SynchronizedClassDemo {

    public void executor() {
        synchronized (SynchronizedClassDemo.class) {
            for (int i =0 ;i < 10; i++) {
                System.out.print(i + " ");
            }
        }
    }


    public static void test() throws InterruptedException {
        SynchronizedClassDemo demo = new SynchronizedClassDemo();
        ExecutorService pool = Executors.newCachedThreadPool();
        pool.execute(demo::executor);
        pool.execute(demo::executor);
        Thread.sleep(2000);
        pool.shutdown();
    }

    public static void test1() throws InterruptedException {
        SynchronizedClassDemo demo = new SynchronizedClassDemo();
        SynchronizedClassDemo demo1 = new SynchronizedClassDemo();
        ExecutorService pool = Executors.newCachedThreadPool();
        pool.execute(demo::executor);
        pool.execute(demo1::executor);
        Thread.sleep(2000);
        pool.shutdown();
    }


    public static void main(String[] args) throws InterruptedException {
        test1();
    }
}

作⽤于整个类,也就是说两个线程调⽤同⼀个类的不同对象上的这种同步语句,也会进⾏同 步。

test 跟 test1() 输出一样的,如下:

text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

同步一个静态方法

java
public class SynchronizedStaticMethod {

    public synchronized static void executor() {
        for (int i=0;i<10;i++) {
            System.out.print( i + " ");
        }
    }

    public static void test() {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(SynchronizedStaticMethod::executor);
        executorService.execute(SynchronizedStaticMethod::executor);
    }

    public static void main(String[] args) {
        test();
    }
}

作用这个类, 会进行同步等待

输出如下:

text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

ReentrantLock

java
public class ReentrantLockDemo {

    private Lock lock = new ReentrantLock();

    public void executor() {
        lock.lock();
        try {
            for (int i = 0; i < 10; i++) {
                System.out.print( i + " ");
            }
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLockDemo demo = new ReentrantLockDemo();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(demo::executor);
        service.execute(demo::executor);
    }
}

输出如下

text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

比较

锁的实现性能等待可中断公平锁锁绑定多个条件
synchronized 是 JVM 实现,ReentrantLock 是 JDK 实现的新版对 synchronized 进行了优化, 添加了自旋锁, 性能差距不大ReentrantLock 可中断,synchronized 不行synchronized 非公平,ReentrantLock 默认非公平,可传参数变为公平ReentrantLock 可以绑定多条件

推荐

除非需要使用 ReentrantLock 高级功能,否则优先使用 synchronized,synchronized 是 JVM 实现的⼀种锁机制,不需要⼿动释放锁,⽽ ReentrantLock 是 JDK 实现的,需要⼿动释放锁,如果没有及时释放锁,那么就可能造成死锁。

Released under the MIT License.