一个最简单的HelloWorld程序,背后也有多个线程。
public static void main(String[] args) { System.out.println("Hello World"); ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); long[] threadIds = threadMXBean.getAllThreadIds(); ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadIds); for (ThreadInfo threadInfo : threadInfos) { System.out.println(threadInfo.getThreadId() + ": " + threadInfo.getThreadName()); } }
输出:
Hello World
5: Attach Listener
4: Signal Dispatcher
3: Finalizer
2: Reference Handler
1: main
java线程的本质
Java 线程 一对一 映射 操作系统内核线程。
java.lang.Thread 中有很多关键的方法是本地方法(Native):
public class Thread { private native void start0(); private native void interrupt0(); private native void setPriority0(); ... }
与内核线程一对一的机制的
优点:提供了 精细强大的线程管理能力。
缺点:其高复杂性使得 并发编程非常困难。
未来Java也会提供类似 Python协程 的轻量级用户线程(Fiber)(Loom)。
Python协程机制可以让一个线程执行多个协程。与多线程模式相比,它 避免了线程切换的开销,甚至 避免线程间的锁机制。
还可用 “多进程 + 协程” 的模式充分利用多核CPU。
Python 生成者-消费者 协程示例:(生产一个,消费一个;单个线程轮换执行生产和消费的过程)
def consumer(): r = '' while True: n = yield r if not n: return print('[消费者] 正在消费 %s...' % n) r = '200-OK' def produce(c): c.send(None) n = 0 while n < 5: n = n+1 print('[生产者] 正在生产 %s...' % n) r = c.send(n) print('[生产者] 消费者返回:%s' % r) c.close() c = consumer() produce(c)
线程状态与方法图
Thread 和 Object 中的 wait、notify 等方法过于晦涩难用。
推荐使用java并发包中的工具来达到同步控制的目的。如,CountDownLatch、CyclicBarrier、Semaphore
创建线程
直接创建 Thread 实例
一般可以通过 Runnable 简单直接的创建线程:
Runnable task = () -> System.out.println("Hello World"); Thread thread = new Thread(task); thread.start(); thread.join();
使用线程池
一般推荐使用线程池来处理稍复杂的多线程场景,以减少创建和销毁线程的开销(包括内存和CPU),降低大量线程“过度切换”的风险。
推荐手动创建线程池,以明确指定运行规则,规避资源耗尽的风险。
- Executors.newFixedThreadPool 和 newSingleThreadExecutor 可能会耗费非常大的内存,甚至OOM
- Executors.newCachedThreadPool 和 newScheduleThreadPool允许最大线程数是 Integer.MAX_VALUE。这可能会导致创建非常的线程,甚至OOM
线程池(ExecutorService)创建示例:
// org.apache.commons.lang3.concurrent.BasicThreadFactory ThreadFactory threadFactory = new BasicThreadFactory.Builder() .namingPattern("example-schedule-pool-%d") .daemon(true) .build(); ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, threadFactory);
ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d") .build(); ExecutorService executorService = new ThreadPoolExecutor( 5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy());
守护线程
如果需要一个长期驻留的线程,但是不希望它影响应用的退出,那么可将该线程设置为 守护线程。
JVM 发现只有守护线程存在时,会结束进程。
具体方法:在启动线程前,调用 Thread.setDaemon(true) 方法:
Thread daemonThread = new Thread(); daemonThread.setDaemon(true); daemonThread.start();
Thread.onSpinWait()
该方法的意思就是“自旋等待”。即,线程在等待期间一直占用着CPU。
这是一直性能优化的技术,用于避免线程切换的开销。
但 Thread.onSpinWait() 方法只是对 JVM 的一个暗示,并没有任何行为上的保障。
JVM 可能会利用 CPU 的 pause 指令。
ThreadLocal
谨慎使用 ThreadLocal ! 注意预防 OOM。
ThreadLocal 提供了一种保存 线程私有 信息的机制。
ThreadLocal 保存的信息在线程的整个生命周期内都有效。
所以可以通过 ThreadLocal 在一个线程关联的 不同业务模块 之间传递信息,如 事务ID、Cookie 等上下文信息。
ThreadLocalMap
ThreadLocal 以 弱引用 的形式被保存。
每个线程(Thread)内部都有一个 ThreadLocalMap 字段来存储属于线程自己的 ThreadLocal 对象。
ThreadLocalMap 内部有一个数组保存这些信息;
数组中的每个元素(Entry),也就是 键值对,都是 弱引用形式的ThreadLocal对象:
class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
通常,弱引用 和 引用队列(ReferenceQueue) 配合垃圾回收机制使用:
创建弱引用对象的同时,将对象注册到一个引用队列中;
当对象的 可达性 成为弱引用时,对象会被添加到该引用队列,用于后续的自定义操作。
public WeakReference(T referent, ReferenceQueue<? super T> q);
但是 ThreadLocal 并没有结合 ReferenceQueue 使用。
也就是说,ThreadLocalMap 中 废弃项的回收依赖于显式的触发;
否则就要等到线程结束,ThreadLocalMap 被回收后,废弃项才会被回收。
ThreadLocalMap 中的几个关键方法,set、remove、rehash,会触发废弃项的回收。
所以在使用ThreadLocal时,为了预防OOM:
- 应用须自己负责删除废弃项:ThreadLocal.remove()
- 不要和线程池配合使用。因为 worker 线程往往不会退出
相关推荐
这套课程既可以作为从零基础开始...课程的主要内容涉及有JAVA基础课程、JAVA多线程与并发编程、数据库开发基础和进阶、Spring Framework、Spring进阶、Spring MVC框架、Spring boot、Java常用类库、Java异常处理等等
《Java多线程核心技术》读书笔记 JDK源码 Java集合框架源码解读(1)——ArrayList、LinkedList和Vector Java集合框架源码解读(2)——HashMap Java集合框架源码解读(3)——LinkedHashMap Java集合框架源码解读(4)——...
《Java后端宝典进阶版》是一本针对Java后端开发者的资源,旨在帮助他们深入学习和掌握Java后端开发的各个方面。该资源涵盖了Java后端开发的核心知识和技术,包括但不限于以下内容: Java基础知识:介绍Java语言的...
java进阶,包含 常用设计模式、线程和并发、spring核心代码、mybatis核心代码、springboot2.0、springcloud 、docker的使用、各类面试题。
java进阶架构师之路的核心知识,面试官逼问知识点,包括基础知识、java集合、JVM、多线程并发、spring原理、微服务、Netty与RPC、Kafka、Zookeeper、分布式缓存等
22 60道必备的Java核心技术面试题!.pdf 23 70道阿里巴巴高级Java面试题!.pdf 24 Java 面试题经典 77 问!.pdf 25 分布式缓存 Redis + Memcached 经典面试题!.pdf 26 搞定 HR 面试的 40 个必备问题!.pdf 27 精选7...
Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...
java多线程编程之核心篇,Java实战,Java技术书籍,Java进阶
java多线程tcp socket server源码 Java学习资料整理 框架 / dubbo监控 / / / / / / / / / / / / / / / / / / / / 收藏 / 技术社区 书籍推荐 计算机基础 计算机科学导论 --(如果不是计算机科班的,应先看看计算机基础...
编者结合自己多年来在Java研发和技术指导岗位上的经验,总结和汲取Java最核心的技术和能力,为广大Java爱好者提供更好的系统学习Java知识的方法和方向。 目录: 第一章:Java入门; 第二章:MyEclipse的基本...
一篇Java进阶架构师之路的核心知识,同时也是面试时面试官必问的知识点,篇章也是包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、...
Java前后开发面试题,大厂进阶之路,基于JavaGuide、Cyc大佬、牛客上的面经及王道考研相关视频,并改进了其中说法矛盾或含糊之处。 包含计算机网络知识、JavaSE、JVM、Spring、Springboot、SpringCloud、Mybatis、多...
java进阶源码分析专题常用设计模式线程与并发锁的使用深度理解synchronized、volatile、cas手写ASQSpring5IOC容器设计原理及高级特性AOP设计原理FactoryBean与BeanFactorySpring事务处理机制Spring JDK动态代理...
Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...
本资源提供了一个循序渐进的学习路径,覆盖了从Java开篇、语法基础、集成开发工具的使用,到面向对象编程、JavaSE进阶学习,再到数据库、前端开发、JavaEE和分布式阶段等多个重要领域。 适用于初学者和有一定经验的...
Java核心系列教程,关于Java核心技术学习积累的例子,是初学者及核心技术巩固的最佳实践。 包括基础语法,OOP,字符串,集合,IO,反射,线程,网络等。未完成模块:阿里Java手册,java8,注解,fork / join,加解密...
java进阶,包含 常用设计模式、线程和并发、spring核心代码、mybatis核心代码、springboot2.0、springcloud G版本、docker的使用、各类面试题。
2023最全的Java大厂面试题合集,共30+专题。包含计算机网络、多线程、数据库、分布式等专题。 微服务架构面试专题...Java 基础核心总结_.pdf Java 工程师进阶知识完全扫盲.pdf BAT面试题汇总及详解(进大厂必看).zip
当然知识点众多,只能说包含核心核心内容,如果你有什么补充或疑问,可以加我的「」交流。还可以关注我的,一起学习,一起进步。本仓库持续更新...,请随意根据知识图谱,我会写一个在线版本,,持续更新中...下面有...
第 12 讲多线程和并行程序设计 第 13 讲数据库开发基础 第 14 讲数据库开发进阶 第 15 讲网站开发基础 第 16 讲网站开发进阶 第 17 讲Spring Framework 介绍及核心组件 第 18 讲Spring进阶,Spring MVC框架基础(上...