当前位置:首页>Java>Java多线程>Java多线程

Java多线程

作者:微学网发布时间:2019-08-11 12:40:38

什么是线程

线程(英语:thread)

是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

线程是独立调度和分派的基本单位

线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。

但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。

一个进程可以有很多线程,每条线程并行执行不同的任务

在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见的,即提高了程序的执行吞吐率。

在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。

什么是多线程

多线程(英语:multithreading)

是指从软件或者硬件上实现多个线程并发执行的技术。

具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。

具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。

软件多线程

即便处理器只能运行一个线程,操作系统也可以通过快速的在不同线程之间进行切换,由于时间间隔很小,来给用户造成一种多个线程同时运行的假象。

这样的程序运行机制被称为软件多线程。

如微软的Windows作业系统和Linux就是在各个不同的线程间来回切换,被称为单人多任务作业系统。

而DOS这类文字接口作业系统在一个时间只能处理一项工作,被视为单人单工作业系统。

除此之外,许多系统及处理器也支持硬件多线程技术

对称多处理机(SMP)系统具有多个处理器,所以具有真正的同时执行多个线程的能力。

什么是Java多线程

Java给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径。

多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。

这里定义和线程相关的另一个术语:进程
一个进程包括由操作系统分配的内存空间,包含一个或多个线程。
一个线程不能独立的存在,它必须是进程的一部分。

一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。

多线程能满足程序员编写非常有效率的程序来达到充分利用CPU的目的,因为CPU的空闲时间能够保持在最低限度。

为什么要学习Java多线程

硬件的驱动以及国内互联网行业的飞速发展

现在 64 核的服务器已经飞入寻常百姓家,大型互联网厂商的系统并发量轻松过百万,传统的中间件和数据库已经不能为我们遮风挡雨,反而成了瓶颈所在。

Java多线程的优点

1. 发挥处理器的强大能力

在多处理器上,多线程可以通过提高处理器资源的利用率来提高系统的吞吐率。

在单处理器系统上也可以获得更高的吞吐率,比如说多线程程序在等待某个同步I/O操作时,还有其他线程可以继续运行。

2. 建模的简单性

完成单任务时,很简单,只要把这件事做好就行。但是在完成多任务的时候,不仅要把活干好,还要考虑不同任务之间存在优先级和时间。

3. 异步事件的简化处理

一部分线程接受客户端请求,另一部分处理器请求。如果是单线程程序的话,处理请求时会停顿导致接受请求阻塞,为了避免这个问题单线程程序必须使用非阻塞的I/O,这种I/O的复杂性要远远高于同步I/O。

4. 响应灵敏的用户界面

用户操作不会被阻塞住

Java多线程的使用案例

如果使用得当,线程可以有效地降低程序的开发和维护成本,同时提升复杂应用程序的性能。

这里列举几个多线程的应用场景,帮助加深理解。

  • 图形用户界面中,多线程可以提供用户界面响应灵敏度。

  • 服务器应用程序中,可以提升资源利用率以及系统吞吐率。比如在tomcat中一部分线程接受请求,另一部分线程处理请求。

  • JVM垃圾收集器中,垃圾收集通常在一个或者多个专门的线程中运行,同时还有个主线程来运行main方法。

  • 矩阵计算,多线程并发执行。

  • 下载大文件时,大文件可以分成多个部分,每个线程下载一部分。

  • 多叉树中搜索N个文件。

  • 假设有个请求,这个请求服务端的处理需要执行3个很缓慢的IO操作(比如数据库查询或文件查询)。

  • web服务器本身;各种专用服务器(如游戏服务器)。

  • 后台任务,例如:定时向大量(100w以上)的用户发送邮件。

  • 异步处理,例如:发微博、记录日志等。

  • 分布式计算。

  • 生产者和消费者模型。

  • 定时任务。

  • Servlet和JSP,多并发时可能有多个客户端请求Servlet,Servlet必须是线程安全的。

  • 远程方法调用。

Java多线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期。

Java多线程生命周期

1. 新建状态

使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

2. 就绪状态:

当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

3. 运行状态:

如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

4. 阻塞状态:

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

  • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

  • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

  • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

5. 死亡状态:

一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

Java多线程的优先级

每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java线程优先级是一个整数,取值范围是 1 (Thread.MIN_PRIORITY ) - 10(Thread.MAX_PRIORITY )。

默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。

但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。