`

【Java核心-进阶】线程

    博客分类:
  • Java
 
阅读更多

一个最简单的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.newFixedThreadPoolnewSingleThreadExecutor 可能会耗费非常大的内存,甚至OOM
  • Executors.newCachedThreadPoolnewScheduleThreadPool允许最大线程数是 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 线程往往不会退出

 

  • 大小: 49.4 KB
分享到:
评论

相关推荐

    Java语言程序设计-进阶篇(原书第10版 中英文)

    3. 多线程:Java提供了强大的多线程支持,进阶篇会介绍线程的创建、同步、通信等技术,帮助读者编写高效的并发程序。 4. 内存管理:Java的垃圾回收机制使得程序员无需手动管理内存,但理解其工作原理对于优化程序...

    Java语言程序设计-进阶篇(原书第8版)

    在Java的世界里,进阶学习主要包括以下几个核心领域: 1. **多线程编程**:Java是并发编程的强大平台,书中会详细介绍Thread类和Runnable接口,如何创建并管理线程,以及如何使用同步机制(如synchronized关键字、...

    Java-JUC-多线程 进阶

    Java-JUC-多线程进阶 Java-JUC-多线程进阶resources是 Java 并发编程的高级课程,涵盖了 Java 中的并发编程概念、线程安全、锁机制、集合类、线程池、函数式接口、Stream流式计算等多个方面。 什么是JUC JUC...

    2011.06 - Java语言程序设计-进阶篇(原书第8版

    以上这些知识点构成了Java语言程序设计进阶篇的核心内容。由于提供的文件信息中包含了重复的下载链接,这里假设这些链接指向的是电子书资源。如果想要获取更多关于Java进阶学习的资料,可以访问这些链接,以获取更...

    Java语言程序设计-进阶篇%28原书第8版

    1. **多线程**:Java是支持多线程编程的语言,书中的章节会详细讲解如何创建和管理线程,包括同步和互斥的概念,以及线程安全的实现方法,如synchronized关键字和Lock接口。 2. **网络编程**:Java提供了丰富的API...

    Java语言程序设计-进阶篇第8版2011

    面向对象编程(OOP)是Java的核心特性之一。进阶篇很可能会深入讲解OOP的概念,包括封装、继承、多态等,并通过实例演示如何在实际项目中运用这些概念来构建复杂的应用程序。 ### 泛型与集合框架 泛型是Java 5引入的...

    java多线程进阶

    Java多线程是Java编程中的核心概念,尤其对于高级开发者来说,掌握多线程的深入理解和应用至关重要。这本书“java多线程进阶”显然旨在帮助读者深化这方面的理解,打通编程中的“任督二脉”,使开发者能够更加熟练地...

    Java 语言程序设计-进阶篇(原书第10版).pdf

    《Java 语言程序设计-进阶篇》是学习Java编程的高级教程,源自原书第10版,针对已经掌握了Java基础知识的读者,深入探讨了Java的高级特性和技术。这本书涵盖了多个关键知识点,旨在帮助开发者提升Java编程技能,...

    Java语言程序设计-进阶篇(原书第8版).

    5. 多线程与并发编程:Java提供了强大的多线程支持,本书会讲解线程的基本概念、线程的生命周期、线程同步机制、并发工具类等,并讨论在多线程编程中可能遇到的问题和解决方案。 6. I/O流与文件操作:Java提供了...

    [Java语言程序设计-进阶篇(原书第8版)]

    在Java的世界里,进阶篇通常会涵盖以下几个核心知识点: 1. **多线程**:Java以其强大的多线程支持而闻名。书中会详细讲解如何创建和管理线程,包括同步机制(如synchronized关键字、wait/notify、Lock接口)、...

    Java语言程序设计-进阶篇

    多线程编程是Java中的一个核心概念,用于实现并发执行任务。Java提供了强大的内置支持来创建和管理线程,主要包括`Thread`类和`Runnable`接口。 **示例:** ```java // 通过继承Thread类创建线程 class MyThread ...

    [Java语言程序设计-进阶篇(原书第8版)](高清)

    以上内容涵盖了Java进阶篇中的几个重要知识点,包括集合框架、异常处理、输入/输出流、多线程编程、泛型与反射以及Lambda表达式与Stream API等。这些知识点不仅能够帮助开发者更加高效地编写Java程序,同时也是深入...

    程序员编程指南 - Java、Spring、SpringBoot等等基础-进阶-源码知识点 & 面试宝典 - 建议使用Obsi

    源码学习部分,你可以探索Java核心库,如ArrayList和HashMap的实现细节,理解其性能优化策略。 接着是Spring框架,它是Java企业级应用开发的基石。Spring提供了依赖注入(DI)和面向切面编程(AOP)等核心功能,极...

    java程序设计进阶版

    在Java编程领域,进阶学习通常涉及以下几个核心知识点: 1. **多线程**:Java作为并发编程的强大工具,深入理解线程的创建、同步和通信至关重要。包括Thread类、Runnable接口的使用,以及synchronized关键字、wait/...

    java基础与进阶资料

    描述中提到“Java类的基础,通俗易懂”,意味着资料可能包含关于类的详细讲解,类是Java中的核心概念,它是对象的模板,定义了对象的状态(数据成员)和行为(方法)。在Java中,一切皆为对象,而类是创建这些对象的...

    Java基础/进阶书籍

    其次,《Java核心技术》通常分为卷I和卷II,由Cay S. Horstmann和Gary Cornell共同撰写。卷I主要讲解Java的基础,包括语法、类库、集合框架、IO流、网络编程等;卷II则深入探讨更高级的主题,如多线程、JVM内部机制...

    java经典面试题目-面经-java-Java语言的进阶概念-常用的库和框架-并发编程-网络编程-Web开发-面经

    Java是一种广泛使用的面向对象编程(OOP)语言,其核心原则包括封装、继承、多态和抽象。封装是将数据和操作数据的方法捆绑在一起,保护数据不受外部非法访问。继承允许一个类(子类)继承另一个类(父类)的属性和...

Global site tag (gtag.js) - Google Analytics