java线程共享模型之管程(锁及其操作)

前言

管程是什么?

管程(Monitor)是一种高级的同步机制,它将共享数据和对这些数据的操作封装在一起,保证在某一时刻只有一个线程能够执行被管程保护的代码。换句话说,管程是一种对对象的同步控制,确保对象的所有操作都是线程安全的。

在 Java 中,管程的实现依赖于 对象锁条件变量。每个对象都有一个与之关联的锁(monitor),以及与该锁相关联的 条件变量(如 wait()notify()notifyAll())。这些机制共同工作,保证线程间的互斥和协作。

下面是一些该文的前置文章。

前文导航


1.线程与进程等基础概念一次理清

2. java中操作线程打断、创建、查看等基础方法的操作


1. 共享带来的问题

1.1 问题演示

我们用一个代码来体现,共享可能带来的问题。

Thread t1 = new Thread(()-> {
   
   
    for(int i = 0; i < 5000; i ++ ) {
   
   
        count ++;
    }
}, "t1");
Thread t2 = new Thread(()-> {
   
   
    for(int i = 0; i < 5000; i ++ ) {
   
   
        count --;
    }
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("count值为:{}", count);

上面的结果,理论上应该是0。但是最终结果却有可能是正数,有可能是负数,可能是0。

三次运行的结果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.2 问题分析

  • 之所以出现这个问题,是为什么呢?那是因为Java中对于静态变量的自增和自减操作不是原子操作,因此需要从jvm字节码的角度来分析。

在这里插入图片描述

在这里插入图片描述

  • 如果是单线程执行的话,不会有任何交错的问题产生,如图:

在这里插入图片描述

  • 但是多线程情况下有可能出现交错运行,导致出错的情况:

在这里插入图片描述

1.3 结论

之所以出现结果不同的情况,根本原因是,线程之间上下文切换导致的指令交错,最终使得结果不同。

1.4 临界区

  • 一个程序运行多个线程没有问题
  • 问题出在多个线程访问共享资源
    • 共同访问也没啥问题
    • 但是多个线程对共享资源访问,产生指令交错,就会出现问题。
  • 一段代码块如果存在对共享资源的多线程读写操作,就称这段代码块为临界区。

eg,下面代码中的临界区:

static int count = 0;

static void increment() {
   
   
    // 临界区
    count ++;
}
static void decrement() {
   
   
    // 临界区
    count --;
}

1.5 竞态条件

多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件。

2. synchronized解决方案

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

2.1 synchronized

  • synchronized : 即 “对象锁”。

​ 它通过采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其他线程想再获得这个【对象锁】时就会被阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文的切换。

在这里插入图片描述

语法
synchronized (对象) {
   
    // 线程1、线程2(blocked)
    //临界区
}
解决
static int count = 0;

static Object object = new Object();

public static void main(String[] args) throws InterruptedException {
   
   
    Thread t1 = new Thread(()-> {
   
   
        for(int i = 0; i < 5000; i ++ ) {
   
   
            synchronized (object) {
   
   
                count ++;
            }
        }
    }, "t1");
    Thread t2 = new Thread(()-> {
   
   
        for(int i = 0; i < 5000; i ++ ) {
   
   
            synchronized (object) {
   
   
                count --;
            }
        }
    }, "t2");
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    log.debug("count值为:{}", count)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值