线程安全(2)

什么是线程安全的(thread-safe)?

在java中,线程安全的指的是代码可以在并发的或者多线程的环境下安全的使用或者共享,并且它们都将按照期望的方式运行。任何代码,类或者对象,如果它们在并发的环境中运行表现出的行为与在非并发环境下表现出的行为不一致,那么它们就不能被称为线程安全的。

本片文章不会非常仔细的介绍线程安全或者Java中的异步处理,我们将通过几个例子来帮助你理解什么是线程安全的然后告诉你如何让你的代码线程安全。

一个non-thread-safe的例子

?
1
2
3
4
5
6
7
8
9
10
11
public class Counter {
   
     private int count;
   
     /*
      * 这个方法不是线程安全的,因为++操作不是原子操作
      */
     public int getCount(){
         return count++;
     }
}
上面的例子不是线程安全的,因为++(自增操作)不是一个原子操作(atomic operation),而是会被拆分成读、更新和写操作(read,update,write)三部分,如果多个线程大约在同一时刻调用getCount()方法,这三个操作可能会互相重合(coincide)或者重叠(overlap),比如:当thread1正在更新数据,thread2此时读取数据,那他将会获得原来的旧数据,最后的结果就是thread2会覆盖掉thread1对数据的增加操作,结果就是:一个数据被丢失了,就是因为程序是并发调用的。


如何在Java中实现线程安全?

要使上面的方法线程安全,可以有很多种方式:

1)使用synchronized关键字来锁定getCount方法,以保证同一时刻只有一个线程可以访问getCount方法,这样做就能避免重合(coincide)或者重叠(overlap)问题。

2)使用AutomicInteger,这样就将++变成了原子操作,因为原子操作是线程安全的,这样做还节省了额外的同步操作的开销。

下面是一个实现线程安全的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Counter {
   
     private int count;
     AtomicInteger atomicCount = new AtomicInteger( 0 );
 
   
     /*
      * 现在这个方法是线程安全的,因为增加了synchronized
      */
     public synchronized int getCount(){
         return count++;
     }
   
     /*
      *这个方法是线程安全的,因为count的增加操作是原子操作
      */
     public int getCountAtomically(){
         return atomicCount.incrementAndGet();
     }
}
关于Thread-Safe的一些重要的点:


这些点在你写线程安全的程序的时候是很有用的,而且也能帮你避免一些很严重的并发问题,比如:竞争条件(race condition)或者死锁

1)不可变的对象(immutable objects)默认就是线程安全的,因为它们的状态一旦创建就不能被改变。由于字符串在Java中就是不可变的,所以它们原本就是线程安全的(关于不可变对象,后期会有相关文章进行说明)。

2)只读的或者被final修饰的变量也是线程安全的。

3)锁机制在Java中是一种实现线程安全的方式。

4)静态变量如果没有被正确的synchronized,那么它将成为线程安全问题的主要原因。静态方法中,如果没引用静态变量,那么这个方法可以说是线程安全的。

5)Java中的一些线程安全的例子:Vector, Hashtable, ConcurrentHashMap, String等。

6)Java中的原子操作是线程安全的,比如从内存中读取一个32位的int值是线程安全的,因为它是原子操作,所以不会与其他线程交错。

7)局部变量也是线程安全的,因为每一个线程都会有属于她自己的一份拷贝。使用局部变量是一种很好的实现线程安全的方式。

8)为了实现线程安全,尽可能地减少多个线程中对象的共享。

9)volatile关键字可以用来指示线程不缓存该变量而是直接从主内存中读取,也可以指示JVM不从多线程的角度来重新排序或者优化代码(not to reorder or optimize code from threading perspective)。

以上就是本文介绍的一些内容。

线程安全是一个比较难以掌握的概念,为了确定程序是否线程安全你需要考虑多并发的情况,另外JVM为了会对代码进行优化,而优化的过程就会涉及到对代码的重新排序,所以看起来是串行的程序在开发环境中运行良好,但并不能保证在生产环境中会同样良好,因为JVM会尽最大可能的进行调整,从而进行一些代码重排序和优化,这样就会导致线程安全的问题。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值