【Java 并发编程】 07 线程安全

1. 什么是线程安全呢?

线程安全并非“线程安全”,大家不要望文生义,所谓的线程安全其实指的是内存的安全,随着操作系统的发展,不再是单核CPU,而是多核多任务,也就意味的进程的并发执行,回想一下是不是可以一边敲着代码,一边听着歌,此时问题来了,为什么这两个进程互不影响呢?操作系统对此做了一系列的保障,是的每一个进程有自己的一块内存空间,进程之间是隔离的,彼此不能互相访问。

每个进程有自己的一块特殊公共的区域,称为堆内存,既然是公共区域,那么一个进程里面的多个线程都可访问的到,这也就是 bug 的起源。一个线程访问公共的成员变量,并对此进行了修改,于是发生线程切换,等回来继续执行的时候发现数据被其它线程进行了修改。由此可见 线程安全是指在没有任何限制的情况下,堆内存中的数据可以被多个线程访问并意外修改。

2. 如何解决线程安全问题呢?

成员变量变为局部变量(线程封闭)—— 没有共享就没有伤害

在这里插入图片描述
学习 java 基础的时候我们知道,内存可以分为堆内存和栈内存,凡是 new 出来的对象都是放在堆内存中的。方法的调用是压栈进行的。👉 成员变量和局部变量的区别,成员变量是类中的变量,随着类的消失而消失,而局部变量是在方法中(局部变量在栈中),随着方法的调用结束而消失。 方法在栈里面,压栈进行的,调用方法是先进后出,方法的调用和栈的存储结构有关,我们称为调用栈。

多个线程可以调用相同的方法,且每个线程可以给方法传不同的参数,也就意味着每个线程都有自己独立的调用栈。
在这里插入图片描述
可见 java 的局部变量是线程安全的,每个线程有自己的调用栈,方法中的局部变量和方法同生共死,且不被其线程共享,回到我们最初线程安全的问题,多个线程可以修改共享变量,此时我们将共享变量变为局部变量,也就是成员变量变为局部变量,不就可以解决线程安全问题了么。可见没有共享就没有伤害。

我有残疾,你随意修改,对我没有差别啦!

我们上述通过将成员变量变为局部变量,可以解决线程安全问题,可是有的时候我们并不想让成员变量变为局部变量,那个怎么办呢,你是否还记得 final 关键字,final 关键字修饰的类我们成为太监类,修饰的变量为太监变量,这是一个残疾的变量,一旦赋了初值,将不会再修改。此时也就意味着多个线程访问该成员变量时,只能读,不能写,即使你写了,也不生效。可见这个方法对线程也是安全的,但是这个方法真的狗。

东西多了就不知道珍惜了— ThreadLocal

回到最初,多个线程访问共享变量,导致线程不安全的问题发生了,可见这个共享变量少,如果多的话,不就没问题了么,就像共享单车,大街上满地都是。每一个线程访问修改共享变量时,拷贝一份到本地,也就意味着,每一个线程都有自己的一套共享变量,是不是可以通过一个map集合来存储 ,
线程名作为key,线程本地的共享变量作为 value 值。每一个线程都有自己的共享变量数据,各自修改各自的,互不影响。具体我们会拿出一篇博客讲解。

我抢到了就加一把锁 — Lock

我们可以通过锁的方式,如果共享单车的数量还是很少,共享资源有限,当我抢到共享资源以后,给共享资源加锁,(不要给共享单车加锁,这里只是讲例子)等不不使用了就释放锁。获取资源前先获取锁,操作结束后释放锁。

class X {
  private final Lock rtl = new ReentrantLock();
  int count;
  public void incream() {
    // 获取锁
    rtl.lock();  
    try {
      count+=1;
    } finally {
      // 释放锁
      rtl.unlock();
    }
  }
}
即使被伤害,世界也要充满爱!—乐观锁

共享变量少,线程多,所以受伤害。如果线程数目少呢,受伤害的概率就变得越来越小,当单线程的时候,也就不存在伤害了。通过锁可以解决线程安全问题,但是每次获取锁和释放锁都需要花费很大的资源,于是CAS 出现了,CAS(Compare And Swap),比较并交换,是乐观锁的一种实现。它适用于并发量较小的情况。乐观锁认为每一次操作大概率不存在线程并发的情况,操作时无需加锁,而是对数据进行版本比较,就像git 和svn 一样,每次push 的时候,都需要检查自己更新前的版本是否和目前版本是否一致,一致才可以推送数据。

此时会后一个ABA问题,例如某一个变量的值为A,某一个线程修改变成了B,后来又被其它线程改回了A,此时的A虽然和以前的A没有任何差别,但是版本号已经不再是原来的版本号。只要数据被修改,版本号就加一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值