关于Java多线程安全问题

Java多线程安全

一、如何理解线程的安全与不安全

     多线程并发执行的情况下,仍能保证数据的正确性,这种现象称为线程安全,反之为线程不安全。

二、导致线程不安全的因素有哪些

1.多个线程并发执行。
2.多个线程并发执行期间,需要访问共享的数据资源,即共享对象。
3.多个线程对共享数据的操作不是原子操作。

三、如何保证并发情况下的线程安全

       线程安全问题主要解决三个问题,可见性,有序性和原子性,Java内存模型(JMM)已经解决了可见性和有序性问题,而原子性需要使用锁来实现。

1.对共享数据的访问进行限制,比如加锁,【synchronized-JVM层面】【lock-JDK层面】等)
       将需要确保原子性的代码或方法使用【synchronized】关键字或锁对象进行加锁,从而使同时只能有一个线程可以进行操作,来保证原子性。
       补充【synchronized】的一些内容,【synchronized】是基于Monitor对象实现同步的,任何对象都有监视器,存在对象的对象头中,也可以理解为对象的锁,一个线程拿到【对象监视器】后,其他线程就不能对该对象进行操作,这里比较抽象,感兴趣的可以拓展下【Java对象的结构组成】,同步代码块采用【monitorenter】和【monitorexit】指令实现,同步方法使用【ACC_SYNCHRONIZED】标记符实现,此内容需要反编译字节码文件查看。JDK1.6之前,synchronized的性能非常差,JDK1.6以后,JVM对synchronized的性能进行了优化,支持自旋锁,偏向锁,轻量级锁,重量级锁。【synchronized】锁分了四种级别,由低到高为【无锁状态】【偏向锁状态】【轻量级锁状态】和【重量级锁状态】,这几个状态会随着竞争的情况逐渐升级,锁可以升级但不能降级,轻量级锁不能重新变为偏向锁,目的是为了提高获得锁和释放锁的效率。锁升级的过程 ,emmm,有点麻烦,大家也可以自己去百度下~

2.基于CAS实现非阻塞同步(CAS需要CPU硬件支持,底层需要调用native方法)
       CAS(CompareAndSwap):对比并交换,需要三个主要数据,【内存地址V】【期望数据A】【需要更新的值B】,仅当预期值A和内存值V相同时,将内存值V修改为B,可以实现非阻塞的数据操作。
       CAS的【ABA】问题,有两条线程,T1将A换成了B,T2又将B换成了A,此时内存地址还是V没有变化,但是已经对数据进行了操作,解决思路,每次修改更新版本号,对数据操作之前,对内存地址V和版本号两个参数进行对比,以确保安全性。

3.取消共享,每个线程一个对象实例(基于ThreadLocal实现)
       ThreadLocal对象类似一个容器,可以给每条线程存储一个对象实例,就像监考人给每个考生发一张答题卡,而不是所有人抢同一个,如【SimpleDateFormat】,该类继承自父类【DateFormat】,继承了一个共享的【Calendar】对象,其【format】方法内部是先将传入的【Date】对象通过【set】方法对【Canlerdr】对象进行设置,然后通过【subFormat】方法,转换为一个字符串进行返回,因此线程不安全。ThreadLocal内部维护了一个【ThreadLocalMap】,暂且可以把他当成HashMap来看,可以将当前ThreadLoal对象和线程需要存储的对象实例,以K-V的形式存在ThreadLocalMap对象中,通过【get()和set()】方法存取。通过取消共享来保证并发安全。同样线程不安全的对象有很多,如:Condition,SqlSession等。

呼 ~ 再继续补充,不太想写代码了....

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值