4.2 synchronized 解决方案

4.2 synchronized 解决方案

      • 1、应用之互斥
      • 2、synchronized
      • 3、思考
      • 4、面向对象改进

1、应用之互斥

为了避免临界区的竞态条件发生,有多种手段可以达到目的。

  • 阻塞式的解决方案:synchronized,Lock
  • 非阻塞式的解决方案:原子变量

本次课使用阻塞式的解决方案:synchronized,来解决上述问题,即俗称的【对象锁】,它采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心多线程操作共享变量

2、synchronized

语法

synchronized(对象) // 线程1, 线程2(blocked)
{
 临界区
}

利用synchronized 解决上一章的counter问题

public class TestCounterSync {
    static int counter = 0;
    static final Object room = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (room) {
                    counter++;
                }
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (room) {
                    counter--;
                }
            }
        }, "t2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.debug("{}",counter);
    }
}

4.2 synchronized 解决方案_第1张图片

使用图来解释为什么synchronize解决了共享问题
4.2 synchronized 解决方案_第2张图片

3、思考

synchronized 实际是用对象锁保证了临界区内代码的原子性,临界区内的代码对外是不可分割的,不会被线程切换所打断。

为了加深理解,请思考下面的问题:

如果把 synchronized(obj) 放在 for 循环的外面,如何理解?
整个循环的 counter ++ 操作时不可分割的,依然可以保证原子性

如果 t1 synchronized(obj1) 而 t2 synchronized(obj2) 会怎样运作?
由于使用的锁对象是不同的对象,并不能保证代码块的原子性

如果 t1 synchronized(obj) 而 t2 没有加会怎么样?如何理解?
没有使用锁的线程依然可以进入到操作共享变量的代码块中,不能保证原子性

4、面向对象改进

把需要保护的共享变量放入一个类

class Room {
    int value = 0;

    public void increment() {
        synchronized (this) {
            value++;
        }
    }

    public void decrement() {
        synchronized (this) {
            value--;
        }
    }

    public int get() {
        synchronized (this) {
            return value;
        }
    }
}

public class TestCounterOop {

    public static void main(String[] args) throws InterruptedException {
        Room room = new Room();
        Thread t1 = new Thread(() -> {
            for (int j = 0; j < 5000; j++) {
                room.increment();
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            for (int j = 0; j < 5000; j++) {
                room.decrement();
            }
        }, "t2");
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        log.debug("count: {}" , room.get());
    }
}

你可能感兴趣的:(Java多线程,java多线程)