什么是线程安全?如何保证线程安全?Java中保证线程安全的方法有哪些?【重要】...

一、什么是线程安全?

简单来说,线程安全是多个线程访问同一段代码,不会造成不确定的结果。

线程安全就是多线程访问时,采用了加锁机制,同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再对共享数据进行操作,确保不会出现数据不一致或者数据污染。

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

二、如何保证线程安全?

先说一下造成线程不安全的三个原因,主要是:

原子性:一个或多个线程操作CPU执行的过程中被中断,互斥性称为操作的原子性。

可见性:一个线程对共享变量的修改,其他线程不能立刻看到。

有序性:程序执行的顺序没有按照代码的先后顺序执行。

可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(也就是其他线程获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作,从而引起不一致。

这里解释一下有序性, 为什么程序执行的顺序会和代码的执行顺序不一致。因为java平台的两种编译器: 静态编译器 (javac)和 动态编译器 (jit:just in time)。

  • 静态编译器是将.java文件编译成.class文件,之后便可以解释执行。
  • 动态编译器是将.class文件编译成机器码,之后再由jvm运行。

有时候,动态编译器为了程序的整体性能会对指令进行重排序,虽然重排序可以提升程序的性能,但是重排序之后会导致源代码中指定的内存访问顺序与实际的执行顺序不一样,就会出现线程不安全的问题。

针对上述三个造成线程不安全的问题,java程序如何保证线程安全呢?

1.针对原子性:

JDK里面提供了很多 atomic类, 比如AtomicInteger、AtomicLong、AtomicBoolean等等,这些类本身可以通过CAS来保证操作的原子性。另外Java也提供了各种锁机制,来保证锁内的代码块在同一时刻只能有一个线程执行,比如使用 synchronized 加锁,保证一个线程在对资源进行读、写时,其他线程不可对此资源进行操作,从而保证了线程的安全性。

2.针对可见性:

同样可以通过synchronized关键字加锁来解决,与此同时,java还提供了 volatile 关键字,要优于synchronized的性能,同样可以保证修改对其他线程的可见性。volatile一般用于对变量的写操作不依赖于当前值的场景中,比如状态标记量等。

3.针对重排序问题:

可以通过synchronized关键字定义同步代码块或者同步方法保障有序性,另外也可以通过 Lock 接口来保障有序性。

三、Java中保证线程安全的方法有哪些?

Java中保证线程安全的方法主要有以下几种:

  1. synchronized关键字: 使用synchronized关键字对共享变量的读写进行同步,能够有效避免多个线程同时访问共享变量而导致的数据竞争问题。

  2. ReentrantLock类: ReentrantLock是一个可重入的互斥锁,与synchronized相比,具有更加灵活的控制能力和更加高级的特性,例如条件变量、公平锁等。

  3. Atomic包下的原子类: 在执行具体操作时使用原子类,例如AtomicInteger、AtomicBoolean等,这些类提供了一些原子性方法,可以在非阻塞和线程安全的情况下对共享变量进行修改。

  4. ThreadLocal类: ThreadLocal类可以为每个线程提供独立的变量副本,使得多个线程之间的共享变量不会相互干扰。

需要注意的是,以上方法都需要结合具体情况进行选择,不同的方法适用于不同的场景。另外,通过避免共享变量的情况也是一种保证线程安全的方式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值