多线程

使用多线程的实践思考

使用多线程的实践思考

刘启春

本文源自一个线上问题引起的思考。诚然多线程是有益的,但使用不当反而会造成系统吞吐能力下降,甚至发生死锁。在使用多线程时我们可能面临下列情况:

  1. 当写的并发代码包含框架类的方法调用,总是可能存在线程安全问题,因为框架在不停升级,我们不能保证它一直线程安全的;
  2. 线程配置不当会引起安全问题,例如:缓存队列溢出、瞬时任务增多导致线程池打满,我们的业务在不断变化,在一个新的上下文环境中,没有人能保证线程配置一直合理;
  3. 多线程让编程更复杂(需要处理更多情况),例如:控制执行顺序、并发访问变量;
  4. 在多线程中进行远程请求容易对下游服务(数据库服务或其他业务服务)造成压力;

通过以上,我们看到在项目中引入一种技术带来的额外风险,有时这种风险不是线性增长而是指数级别,因此从这些角度看应该谨慎使用多线程。好的实践是先寻找其他解决方案,最后再考虑使用多线程,把多线程当作性能扩展的最后一道防线。

如果不用多线程就不存在上述的问题,我们假设使用多线程背景下来总一些实践技巧。

Java|ThreadLocal

刘启春

ThreadLocal 是线程本地变量,用与在线程上下文中共享变量。

ThreadLocal 经常用在框架中,例如 SpringSecurity 用它存储当前请求的操作用户。

  • ThreadLocal 既线程本地变量,可以使变量为线程私有,避免状态共享出现线程安全问题。
  • InheritableThreadLocal 继承 ThreadLocal 实现,可以使子线程共享父线程的 ThreadLocal。
  • FastThreadLocal 是 Netty 实现的一个 ThreadLocal,当从 FastThreadLocalThread 访问时,可以产生更高的访问性能,在 FastThreadLocal 内部使用数组中的索引来查找变量,而不是使用哈希码和哈希表。

深入理解Java多线程(三):JUC基础篇

刘启春

这篇文章主要侧重讲 JUC 的多数类的使用,文章里贴了很多练习的代码,可以通过代码更加深刻的了解这些类的功能。

这篇文章主要总结了 volatile、原子类、ReentrantLock、CountDownLatch、CyclicBarrier、Phaser、Semphore、Exchanger 的使用,然后进行了一些对比。

深入理解Java多线程(二):多线程问题学习总结

刘启春

学了一段时间多线程方面的知识了总感觉掌握的知识有些散乱,在网上搜了一些面试问题总结梳理一下。

多线程

java 中有几种方法可以实现一个线程?

Java 中有四种方式实现一个线程。

  1. 通过实现一个 Runnable
  2. 继承 Thread 并重写 run 方法
  3. 继承 Callable,用 Future 接收可以实现异步调用
  4. 使用线程池(executer)提交作业

如何停止一个正在运行的线程?

使用 suspend 可以挂起一个线程,使用 stop 可以终结一个线程,但这些方法已经不推荐使用,存在安全性问题,停止一个线程最好的方式是让它自然结束,常用的方式是使用一个 volatile 变量来控制线程是否继续运行。

suspend、stop 不再推荐使用的原因是容易引发死锁,当一个线程持有锁的时候它被挂起或暂停掉了,此时锁还没有释放,其他线程无法获取所就会出现思索,最好的方式是让线程自然结束。

深入理解Java多线程(一):线程基础知识总结

刘启春

Java 线程的实现

Java 线程在 JDK1.2 之前,是基于称为“绿色线程”的用户线程实现的,而在 JDK 1.2 中,线程模型替换为基于操作系统原生线程模型来实现,因此,在目前的 JDK 版本中,操作系统支持怎样的线程模型,在很大程度上决定了 Java 虚拟机的线程是怎样映射的,这点在不同平台上没有办法达成一致,虚拟机规范中也并未限定 Java 线程需要使用哪种线程模型来实现。

举个例子,对于 Sun JDK 来说,它的 Windows 版与 Linux 版都是使用一对一的线程模型实现的,一条 Java 线程就是映射到一条轻量级进程之中,因为 Windows 和 Linux 系统提供的线程模型就是一对一的。

总结:java 线程与操作系统线程是一对一的,在 linux 上通过调用 pthread 库创建线程。