4 Java并发编程—设计模式

本文探讨了不可变性模式在避免数据修改中的优势,如线程安全和性能提升,包括final类、无状态对象和Copy-on-write策略。还讲解了ThreadLocal的使用场景、内存泄露问题以及生产者消费者模式、线程池和两阶段终止线程的最佳实践。
摘要由CSDN通过智能技术生成
Immutability模式(避免写)

不变性模式

不变性就是对象一旦被创建之后就不可以被改变,只有读操作,没有写操作。那么就线程安全

无状态也是线程安全,无状态意思就是没有属性,没有属性就不能修改,那么就线程安全了,性能好

不可变性的类:

  • class 和 属性加final
  • 类里面没有修改方法,只有读方法
  • 属性如果是对象,也需要这个属性的对象 满足前面两点
    • 如果这个属性不满足这点,那么这个类是线程安全的,但是这个属性不是线程安全的

使用不可变性类,如果要改变类的值,方法里面新建一个不可变性类就好啦

​ 就像String replace方法,返回的是新的String

为了减少不可变性类对象的数量,可以用享元模式

  • 享元模式就是一个对象池,新建对象的时候,在对象池看一下有没有这个对象,如果没有就创建,如果有就返回现有的对象
  • Long用了一部分享元模式,LongCache对象里面有值为-128~127的对象池,Long调用valueOf方法时,如果在这个范围内,使用LongCache里的对象池返回对象
Copy-on-write

写时复制,适用于读非常多,写非常少且数据量不大的场景

Java里面,cow都是复制整个数据结构的,所以比较耗内存,但是上面的场景读的性能非常好

函数式编程,Java 中的基本数据类型 String、Integer、Long都有用

操作系统的父子进程创建也用到,新建子进程的时候,父子进程公用一个内存地址,后面子进程进行修改时,才会给子进程分配一个内存空间,这也是延时

线程本地存储—ThreadLocal(避免共享)

避免变量共享,一人一个,就不需要对这个变量加锁

局部变量也是避免共享的一种方式,但是并发量高的时候会产生大量的局部变量

​ 调用量=局部变量数,线程数=ThreadLocal数

【还是不太懂ThreadLocal的内存泄露,不过用过之后删掉数据就不会泄露了】

Thread-Per-Message模式:最简单实用的分工方法

就是一个主线程接收请求,每一个新来的任务都创建一个新的线程

在Java里面,新建线程成本很高,而且并发量大很容易oom

Thread-Per-Message 模式会为每一个任务都创建一个线程,在高并发场景中,很容易导致应用 OOM,那有什么办法可以快速解决呢

只能改jvm内存配置,增大jvm新生代的大小,长期解决,引入NIO或AIO,netty 就是这么干的

Worker 丨Thread模式:如何避免重复创建线程?

其实就是线程池,worker thread 就相当于工人,线程池里的线程,一直在队列里面拿任务执行

两阶段终止模式:优雅地终止线程

直接终止线程十分生硬,强行终止线程

两阶段终止模式是先用interrupt()方法,把线程从休眠状态唤醒成运行状态【第一阶段:发出终止指令】。然后线程再自己执行run方法,执行到设置的标志位时自行终止【第二阶段:相应终止指令】

(线程池的shutdown方法终止的时候,还在执行的线程和队列里的线程还可以执行。shutdownNow是强行终止所有线程)

【catch 线程的 的中断异常之后,会重置线程的中断状态,直接使用线程的isinterrupt方法结果是没有中断。所以需要在catch中断异常之后,重新设置中断状态】

示例:

【terminated 标志位 要加volatile,因为start方法里面新建了一个线程,导致stop方法有可见性问题,要加volatile。原子性问题不用考虑】

class Proxy {
  // 线程终止标志位
  volatile boolean terminated = false;
  boolean started = false;
  // 采集线程
  Thread rptThread;
  // 启动采集功能
  synchronized void start(){
    // 不允许同时启动多个采集线程
    if (started) {
      return;
    }
    started = true;
    terminated = false;
    rptThread = new Thread(()->{
      while (!terminated){
        // 省略采集、回传实现
        report();
        // 每隔两秒钟采集、回传一次数据
        try {
          Thread.sleep(2000);
        } catch (InterruptedException e){
          // 重新设置线程中断状态
          Thread.currentThread().interrupt();
        }
      }
      // 执行到此处说明线程马上终止
      started = false;
    });
    rptThread.start();
  }
  // 终止采集功能
  synchronized void stop(){
    // 设置中断标志位
    terminated = true;
    // 中断线程 rptThread
    rptThread.interrupt();
  }
}
生产者消费者模式

线程池,队列都属于这种

好处:支持异步,可以平衡消费者生产者速度差异,支持批量任务(比如写日志,可以先一条一条排到队列,然后再批量批量地写入磁盘,提高效率)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沛权

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值