Java juc系列7 —— 线程安全

Java JUC系列目录链接

Java 线程池核心原理解析

何为线程安全

直接上个伪代码:

boolean a = 多个线程共享变量;
boolean b = 存在写操作;
boolean c = 写操作导致数据冲突;

if( a && b && c ) {
	存在线程安全问题;
}

文字描述就是,只有多个线程共享变量线程存在写操作操作导致数据冲突同时满足的情况下,才会存在线程安全问题。

如何解决线程安全

解决线程安全还不简单,不就是让上面的if的条件不为真嘛!显而易见,只要a,b,c中有一个或多个恒为false,就不会出现线程安全问题。
下面我们就给出具体解决方案:

  • ‘a’ always == false:
    即:多个线程不共享变量。在这之前我们先来想一下,为什么多个线程会共享变量?联系Java虚拟机模型,我们知道,如果我们的变量是存在堆区的,那么这个变量就会被多个线程所共享。明白了这一点就好办了,*方案1我们直接把变量定义到栈,即局部变量,那不就不会跟其他线程共享啦,自然旧解决了线程安全的问题。
    伪代码如下:

    class A {
    // int a = 1;
    	public void test(){
    		int a = 1;
    	}
    }
    

    我们把原来的全局变量a移到了局部变量,这样a就会被存放到方法’test’的方法栈中,自然就不会有线程安全的问题了。

    如果说你非要犟,我就是要把变量存到堆中去,也要不让线程之间共享变量,那怎么办?
    别慌,我们还是有办法的,如果大家听过ThreadLocal这个类,那一定不会束手无策了。*方案2ThreadLocal为每一个线程需要的变量提供一个本地的副本,这样就不会有线程安全问题啦。什么意思?简单来说就是,你线程不是想要a变量嘛,我给你们线程没人一个a变量,但是你们都只能各玩各的,不许去玩别人的。但是使用ThreadLocal有一点要注意,你创建的这个对象如果存放在堆中的话,还是可能会导致线程安全问题的。

  • ‘b’ always == false:
    即:线程不存在写操作。既然你说写操作会有线程安全问题,那我们来个绝的,既然写了问题这么多,大家都别想写了!*方案3直接把变量变成final类型,直接上伪代码:

    	class A {
    	final int a = 1;
    	}
    

    虽然这个解决方案有点绝,但也不失为一总可选方案呀。

  • ‘c’ always == false:
    即:写操作不导致数据冲突。写操作不冲突?emm…让我想想,既然你们都一起来搞会有冲突,那这样,你们排队一个个来玩,那不就完了嘛。这就是我们最熟悉的——‘锁’。*方案4我们使用锁来确保线程依次对变量进行操作,这样就避免了线程安全问题,至于怎么加锁synchronized,Lock啥的随便你选,我就不说了。
    你说什么?加锁性能低?没办法了,只能掏出这个了——‘CAS’,即为乐观锁。想要确保线程的写操作不导致数据冲突,加锁确实是性能较低的一种解决方案,乐观锁看起来名字像是锁,其实是一种无锁机制,原理想必你们背面试题肯定是十分熟练了。顺便一提的是,传统CAS可能会导致‘ABA’问题,所以有人在乐观锁的实现中加入了时间戳(版本号)。

结语

本文只是从广度上简介了关于线程安全的一些问题,关于文中提到的一些深度问题,比如jvm模型,ThreadLocal啥的与本文无关,这里就不再赘述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值