什么是线程安全

Posted 黑面书生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是线程安全相关的知识,希望对你有一定的参考价值。

如果这个是面试官直接问你的问题,你会怎么回答?

一个专业的描述是,

当多个线程访问一个对象时,如果不用进行额外的同步控制或其他的协调操作,调用这个对象的行为都可以获得正确的结果,我们就说这个对象是线程安全的

那么我们如何做到线程安全?

实现线程安全的方式有多种,其中在源码中常见的方式是,采用synchronized关键字给代码块或方法加锁,比如StringBuffer

那么,我们开发中,如果需要拼接字符串,使用StringBuilder还是StringBuffer?


场景一:

如果是多个线程访问同一个资源,那么就需要上锁,才能保证数据的安全性。

这个时候如果使用的是非线程安全的对象,比如StringBuilder,那么就需要借助外力,给他加synchronized关键字。或者直接使用线程安全的对象StringBuffer


场景二:

如果每个线程访问的是各自的资源,那么就不需要考虑线程安全的问题,

所以这个时候,我们可以放心使用非线程安全的对象,比如StringBuilder

比如在方法中,创建对象,来实现字符串的拼接。

看场景,如果我们是在方法中使用,那么建议在方法中创建StringBuilder,这时候相当是每个线程独立占有一个StringBuilder对象,不存在多线程共享一个资源的情况,所以我们可以安心使用,虽然StringBuilder本身不是线程安全的。


什么时候需要考虑线程安全?

1,多个线程访问同一个共享资源

2,资源是有状态的,比如我们上述讲的字符串拼接,这个时候数据是会有变化的


41-什么是线程安全?

其实说的是内存变量安全,如何理解?

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问, 直到该线程读取完,释放了锁,其他线程才可使用。
这样的话就不会出现数据不一致或者数据被污染的情况。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后
更改数据以至于所得到的数据是脏数据。这里的加锁机制常见的如:synchronized

局部变量一定是安全的,因为私有。

那成员变量呢,因为共享,就不安全,怎么办?

可以拷贝很多份,每个线程一份,比如,放到ThreadLocal<变量>
说的直白一些,就是把堆内存中的一个数据复制N份,
每个线程认领1份,同时规定好,每个线程只能玩自己的那 份,不准影响别人的。
需要说明的是这N份数据都还是存储在公共区域堆内存里的

ThreadLocal就是,把一个数据复制N份,
每个线程认领 一份,各玩各的,互不影响。

ThreadLocal是为每个线程创建一个单独的变量副本,每个线程都可以改变自己的变量副本而不影响其它线程所对应的副 本。



我理解的线程安全,就是,
一个共享变量,多个线程访问,在不通过额外加锁的情况下,
就能保证多个线程操作这个数据符合预期,确保数据的安全(或一致)性
那么,这个变量就是线程安全的。

1. 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
2. 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。


get():返回此线程局部变量当前副本中的值
set(T value):将线程局部变量当前副本中的值设置为指定值
initialValue():返回此线程局部变量当前副本中的初始值
remove():移除此线程局部变量当前副本中的值

ThreadLocalMap用键值对方式存储每个线程变量的副本,
key为当前的ThreadLocal对象,value为对应线程 的变量副本。

42-共享变量一定不安全吗?

不,如果前面加final,就是常量,常量只有一份,且不变,所以,就是安全的。
任何线程都动不了我,当然安全了。


比如我把数据放到公共区域的堆内存中,但是始终都只会有1个线程,
也就是单线程模型,那这数据肯定是安全 的。

再者说,2个线程操作同一个数据和200个线程操作同一个数据,
这个数据的安全概率是完全不一样的。肯定线程 越多数据不安全的概率越大,
线程越少数据不安全的概率越小。
取个极限情况,那就是只有1个线程,那不安全概 率就是0,也就是安全的。
70-线程安全
线程安全就是多线程访问时,
采用了加锁机制,
当一个线程访问该类的某个数据时,进行保护,
其他线程不能进行访问直 到该线程读取完,
其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,
有可能 出现多个线程先后更改数据造成所得到的数据是脏数据


一个线程想要执行synchronized修饰的方法里的代码,
首先是尝试获得 锁,如果拿到锁,执行synchronized代码体的内容,
如果拿不到锁的话,这个线程就会不断的尝试获得这把锁,直到拿到 为止,
而且多个线程同时去竞争这把锁,也就是会出现锁竞争的问题。
我对任何唾手而得,快速,出自本能,即兴,含混的事物没有信心。我相信缓慢,平和,细水长流的力量,踏实,冷静。我不相信缺乏自律精神和不自我建设,不努力,可以得到个人或集体的解放。

以上是关于什么是线程安全的主要内容,如果未能解决你的问题,请参考以下文章

HashMap 和 ConcurrentHashMap 的区别

什么是线程安全?

什么是线程安全?

什么是线程安全?

什么是线程安全?

怎样去写线程安全的代码(Java)