线程安全问题的原因和解决方案

一.线程安全
1.概念: 多个线程同时访问一个对象时,由于操作系统调度线程时是随机的,抢占式,其随机性导致了多线程环境下代码运行的结果不符合我们的预期,即在单线程环境应该的结果,则说这个线程是不安全。
2.产生原因
(1)抢占式执、随机调度。 多个线程的调度执行,可以视为是"随机的",虽然有调度算法,但是在应用程序上来看确实没有规律可言。所以我们在写多线程的时候,尽量保证在任何一种调度的情况下都能有正确的运行结果。
(2)多个线程修改同一个变量。
【注】一个线程修改一个变量不会产生线程安全;
多个线程读取一个一变量不会产生线程安全;
多个线程修改不同的变量不会产生线程安全。
(3)原子性: 如果某些修改操作不是一条指令就能完成的,而是cup执行多条指令,就会导致cpu执行到某个指令时,就被调度走,去执行其他的指令,从而对运算结果造成了影响,造成线程不安全。
(4)内存可见性问题: 可见性是指,当多个线程并发访问共享变量时,一 个线程对共享变量的修改,能够即使被其它线程看到。
(5)指令的重排序:可能编写的代码,不会按照顺序执行,JVM为了提高程序的整体效率可能会对代码进行优化,其中就有对代码顺序进行优化。
二、线程安全的解决方案
一般解决多线程的安全问题,都是针对上面第三点。把修改操作打包后变成原子性的操作指令——加锁。一般来说有两种锁:(1)Synchronized获取不到,等待再次获取(2)Java里面还有一种锁Reetrantle,这个锁可以有这个策略,获取不到就放弃
【注】1.如果两个线程针对同一个对象加锁,会产生阻塞等待(锁竞争/锁冲突),如果两个线程针对不同的对象加锁,不会阻塞等待(锁竞争/锁冲突),这两个线程都能获取到各自的锁,不会阻塞等待;
2.加了Synchronized之后,进入方法就加锁,出了方法就会解锁,如果两个线程同时对同一对象尝试加锁,此时一个能获取锁成功,另一个只能阻塞等待,一直阻塞到刚才的线程释放锁,当前线程才能加锁成功 。
3.一个线程加锁,一个不加锁,此时无锁竞争,只有两个线程均加锁才有锁竞争。
使用关键字:synchronized(对象引用:比如this)只能锁一个对象
(1)可以修饰普通方法: 锁的是当前实例对象

public class SynchronizedDemo {
   public synchronized void methond() {
   }
}

(2)可以修饰静态方法: 锁的是当前类的class对象(该类所有对象共享)

public class SynchronizedDemo {
   public synchronized static void method() {
   }
}

(3)可以修饰代码块: 锁的是synchronized括号里的对象

public class SynchronizedDemo {
    public void method() {
        synchronized (this) {
        }
    }
}

【注】 任何对象(成员变量,局部变量,静态变量,类对象)都可以在synchronized里面作为对象,我们不关心锁的对象究竟是谁,是什么形态,只关心是不是多个线程锁的是同一个对象,锁同一个对象有锁竞争,锁不同的对象没有。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值