JUC学习笔记——共享模型之管程( 二 )

  • 这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换
  • 我们先来介绍synchronized的语法:
    // 线程1, 线程2 都使用同一对象作为锁,这样一个运行,另一个处于blocked阻塞synchronized(对象){临界区}我们再给出相关代码示例:
    // 我们创建一个room对象来作为锁,注意处理共享问题的线程需要绑定同一个锁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);}我们做简单解释:
    • synchronized相当于一个方法用来设置一个房间
    • room对象相当于一个锁,这个锁控制着房间,而房间中放着所有对应的synchronized里面的代码
    • 多个线程谁先进入room就可以获得钥匙,然后如果想要进入这个房间操作,只有有钥匙的线程才可以
    • 当该线程操作结束后,就会主动将钥匙让出来,其他线程就可以进行抢夺钥匙,哪个线程获得钥匙就可以继续操作
    • 同时我们需要注意时间片结束并不意味着解开锁,就算轮到其他线程的时间片,他们也不能进入到房间里去执行他们的代码
    synchronized思考synchronized 实际是用对象锁保证了临界区内代码的原子性,临界区内的代码对外是不可分割的,不会被线程切换所打断 。
    我们简单给出三个思考问题:
    // - 如果把 synchronized(obj) 放在 for 循环的外面,如何理解?-- 原子性会将for循环也作为原子性的一部分,会连续执行5000次之后才释放锁给另一个线程使用// - 如果 t1 synchronized(obj1) 而 t2 synchronized(obj2) 会怎样运作?-- 锁对象两个线程使用不同的锁,自然就对应不同的房间,不具有安全性// -如果 t1 synchronized(obj) 而 t2 没有加会怎么样?如何理解?-- 锁对象一个线程使用锁,另一个不使用,自然不具有互斥关系,不具有安全性对象解决共享问题我们同样也可以直接采用一个类和synchronized搭配来解决共享问题
    // 我们自定义一个类,里面装有数据,我们采用synchronized解决共享问题class Room {// value值是属于room对象的int value = https://www.huyubaike.com/biancheng/0;// 这里的 synchronized 里面的 this 指的是创建的类的实际对象public void increment() {synchronized (this) {value++;}}public void decrement() {synchronized (this) {value--;}}public int get() {synchronized (this) {return value;}}}@Slf4jpublic class Test1 {public static void main(String[] args) throws InterruptedException {// 注意:这里线程1,2采用的是一个roon对象,所以他们的value值是共享的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());}}synchronized方法使用我们的synchronized有时也会用于类的方法中,具有不同的意义:
    // 首先是将synchronized放在普通的方法上:下面两个class是等价的,这里的this指的是对象本身class Test{public synchronized void test() {}}class Test{public void test() {synchronized(this) {}}}// 再者就是将synchronized放在静态方法上:下面两个class是等价的,这里的Test.class指的是类本身class Test{public synchronized static void test() {}}class Test{public static void test() {synchronized(Test.class) {}}}"线程八锁"思考题我们来给出面试常用的线程八锁思考题来进行自身检测:

    经验总结扩展阅读