两个线程频繁进行上下文切换引发的线程安全问题分析以及使用synchronized关键字的解决方案

两个线程频繁进行上下文切换引发的线程安全问题分析以及使用synchronized关键字的解决方案

线程安全问题的例子

两个线程频繁进行上下文切换,如果这个过程中,这两个线程共用了同一个资源,这里是counter静态变量,那么就可能会出现线程安全问题,如下图:

在这里插入图片描述

以上的结果可能是正数,负数,零,为什么呢?因为Java中对静态变量的自增,自减并不是原子操作,要彻底理解,必须从字节码来进行分析。

例如对于i++而言(i为静态变量),实际会产生如下的JVM字节码指令:

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

而对应i–也是类似:

getstatic  i  //获取静态变量i的值
iconst_1      //准备常量0
isub          //自减
putstatic     //将修改后的值存入静态变量i

分析:假设刚开始时静态变量i的值是0,假设t1线程先得到cpu的分时时间片,执行了i++对应的前三个字节码指令,这时候t1线程的时间片用完了,那么这个时候t2线程就得到了cpu的时间片,假设也是执行了i–对应的前三个字节码指令,注意无论是i++对应的前三个字节码指令还是i–对应的前三个字节码指令,此时取得的i静态变量都是0,这个时候t2线程的时间片用完了,t1线程得到时间片,执行i++对应的第四条字节码,把i进行++操作,i从0变成1,然后把i的值存起来,这时候t1线程的时间片用光了,t2线程得到时间片,执行i–对应的第四条字节码,i从0变成-1,然后把i的值存起来,因此执行t1线程执行完i++操作,t2线程执行完i–操作,它的最终结果是i=-1,而不是i=0,这就是说明了,多个线程共享一个资源,会出现线程安全问题。

线程安全问题的解决

synchronized关键字不加在方法上

那么上述的线程安全问题需要怎么解决呢?

第一种解决方案,使用synchronized关键字,语法:

synchronized(对象)//这个对象就是一把锁,要求对象必须是唯一的
{
    临界区
}

上述用的synchronized关键字解决线程安全问题的原理:给临界区加上一个锁,这个锁是唯一的,一个线程执行到这个临界区的时候,都会手里面握着一把锁,下一个线程如果也想要执行临界区内的代码,手里面必须也要握着一把同样的锁,但是如果上一个线程没有执行完的话,它就不会释放这把唯一的锁,所以后面的线程就不能执行这块临界区的代码,后面的线程会进入blocked阻塞状态,只有当前面一个线程临界区代码完毕,释放了唯一锁,这个时候后面的线程才能够获得这把锁去执行临界区的代码。

synchronized关键字的使用如下图:

在这里插入图片描述

synchronized实际是用对象锁保证了临界区内代码的原子性,比如上图中的例子中,counter++代码和counter–代码都对应着4条JVM字节码指令,synchronized可以保证这4条JVM字节码指令整体运行,不容分割,不会被线程切换打断。

synchronized关键字加到方法上

1.加到非静态方法上,如下:

class Test{
    public synchronized void test(){
        临界区
    }
}
//上面等价于
class Test{
    public void test(){
        synchronized(this){
            临界区
        }
    }
}

2.加到静态方法上,如下:

class Test{
    public synchronized static void test(){
        临界区
    }
}
//等价于
class Test{
    public static void test(){
        synchronized(Test.class){
            临界区
        }
    }
}

如果synchronized关键字应用到了许多个方法上,并且这些方法都是用的同一把锁,那么这些方法都是互斥的,什么意思呢?就是如果有多个线程同时调用这些方法,那么每次只能有一个线程调用其中的一个方法,如下图:

在这里插入图片描述

方法用的锁不同,那么它们不会互斥,如下图:

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr-X~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值