前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >并发编程(一)

并发编程(一)

作者头像
小土豆Yuki
发布2021-09-24 10:42:07
2180
发布2021-09-24 10:42:07
举报
文章被收录于专栏:洁癖是一只狗洁癖是一只狗

java内存模型

上图就是我们的java内存模型

  • 共享变量存储在主内存中,每个线程都会访问
  • 每个线程指存储该线程对共享变量的副本
  • 线程不能直接操作主内存,只有先操作工作内存之后才能写入主内存
  • 工作内存和java内存模型一样也是一个抽象的概念,他其实并不存在,他涵盖了缓存寄存器,编译器优化以及硬件
代码语言:javascript
复制
public class Demo10 {
    private int x=0;
private int  count(){
return x++;
    }
}

上面是我们很一般的代码,在多线程中执行count()会有什么问题

发现x的值被覆盖了,为什么会出现这样的呢

  • 从主内存中读取x=0的值
  • 给x+1
  • 回写到主内存

上面三个步骤不是原子性的,当多个线程同时执行,有可能线程1在步骤1和步骤2之间另外一个线程2执行步骤1,此时线程2再次执行步骤2执行x+1,此时线程1也开始执行x+1,同时执行就会导致数据被覆盖的结果

我们再来看一个例子

代码语言:javascript
复制

public class test {
private int value = 0;

public void set(int value){
this.value = value;
  }

public int get(){
return this.value;
  }
}

上面代码在多线程中执行,有什么问题呢

发现当线程1已经更新的value的值,但是线程2获取的到值还是value=0.这就是可见性问题

我们再看看如下代码,有什么问题

代码语言:javascript
复制
public class Singleton {
    private static Singleton instance = null;
public Singleton() {
    }
private static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
return instance;
    }
}

上面代码是一个经典的懒汉+同步操作的单例模式,但是他是还存在那些问题呢,首先我们要知道创建一个实例对象并不是一步就可以创建的,而是按照下面步骤执行的

代码语言:javascript
复制
instance = new Singleton();
  1. 分配内存地址
  2. 初始化对象
  3. 实例变量指向刚才分配的内存地址

但是由于编译器进行指令重排序可能是1->3->2的顺序,就会导致实际上对象还没有初始化完成,而对象的属性是空,最终可能导致空指针,这个就是有序性问题

上面都是多线程中一起的并发问题,那我们如何解决呢

局部变量

局部变量由于仅存在线程中的内存中,不会出现共享变量的情况

ThradLocal

每个线程都有一个integet对象,虽然每个线程都会从主内存中把integer对象拷贝到工作内存中,但是线程1和线程2复制的对象并不是同一个对象,每个对象都会只会被一个线程操作,所以不存在共享变量,也就不会存在并发问题

不可变类

所谓的不可变对象是指已经常见,就对外的状态就不会改变的对象,如果一个对象的状态是恒古不变的,那么自然就不存在并发问题,因为对象是不可变的,所以无论多少个线程,对他做什么操作,他都是不变的,

CAS类

CAS意思就是Compare And Swap,比较并置换,CAS使用了3个基本操作数,内存地址V,旧的预期值A,要更新的新值B,只有当内存地址的对应的值和旧的预期值一样就会用新值B,才会将内存地址V对应的值更新为新的值B,否则循环操作,知道成功

我们知道JUC里面的AtomicInteger就是使用CAS思想,在AtomicInterger可以保证多线程下线程安全是依赖一Unsafe的实例,Unsage类提供硬件级别的原子操作,因为java是无法直接访问操作系统底层硬件,为此java使用native方法来扩展这部分功能,其中UnSafe类就是一个操作入口,UnSafe提供几种功能,其中包括分配和释放内存,挂起和恢复线程,定位对象字段内存地址,修改对象的字段值,CAS操作。

Synchronized和Lock

他们是进行加锁,是悲观锁的策略,在多线程中只有一个线程可以得到执行,

首先是两个线程抢占锁,但是线程1,抢到了锁,而线程2就会进入队列,当线程1执行完之后,通知线程2,你可以尝试抢占锁了,线程2就会尝试抢占锁,抢到之后才会执行代码

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-09-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洁癖是一只狗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档