Java 多线程之临界区与竞态条件(九)

博客围绕Java共享资源问题展开。以两个线程对静态变量自增自减为例,指出Java中静态变量自增(减)非原子操作会引发问题。介绍了临界区和竞态条件的概念,给出阻塞(synchronized、Lock)和非阻塞(原子变量)两种解决方法,还说明了synchronized在互斥和同步上的区别。
摘要由CSDN通过智能技术生成
正文

Java 体现共享资源的问题

两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果为 0 么?

public class Test2 {
    static  int j = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                j++;
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                j++;
            }
        });

        thread.start();
        thread2.start();
        thread.join();
        thread2.join();
        System.out.println(j);
    }
}

运行结果

Disconnected from the target VM, address: '127.0.0.1:10483', transport: 'socket'

1543

Process finished with exit code 0

问题分析

因为 Java 中对静态变量的自增(减)并非原子操作,从字节码角度分析就可以知道原因了

以 j ++( j 为静态变量)为例,看起来是一条指令,实际上在 JVM是以下效果

getstatic  j //获取静态变量 j 的值
iconst_1	 //准备常量 1
iadd		 // 自增
putstatic	 // 将修改后的值存入静态变量

在 Java 的内存模型中,完成静态变量的自增(减),需要在主存和工作内存中进行数据交换的。


临界区
  • 一个程序运行多个线程会发生的问题
    • 访问共享资源,若多个线程对共享资源读写操作时发生指令交错,就会出现问题
  • 一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区
static int i = 0;

static void increment()
//临界区
{
    //要知道,一个 i++ 在字节码层面是分为四个步骤的,包含读写
    i++;
}

static void decrement()
//临界区
{
    i--;
}
竞态条件

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

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

注意

Java 中互斥和同步都可采用 synchronized ,但还是有区别的

  • 互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码
  • 同步是由于线程执行的先后、顺序不同,需要一个线程等待其他线程运行到某个点

synchronized

语法–加对象

synchronized(对象,任意的java对象)
{
    //临界区
}

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

语法–加方法

class Test{
    public synchronized void test(){

    }
}

等价于
class Test{
    public  void test(){
         synchronized(this){

         }

     }
}

不加 synchronized 的方法,不需要获取锁,无视阻塞,不遵守规则的人

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值