多线程概述:
java中的多线程是一个同时执行多个线程的进程。线程是一个轻量级的子进程,是基本的执行单元。多线程和多进程都用于实现多任务处理。
多线程使用进行的共享内存区域。它们不分配单独的内存区域以节省内存,并且线程之间的上下文切换比进程花费的时间更少。
进程:进程是一个程序的动态体现,是操作系统资源分配的最小单位
线程:线程是存在于线程中的并行的任务,是任务调度的最小单位
在单核cup的计算机中,同一时刻实际上只是在运行一条指令,执行一个任务,但是由于cpu的速度飞快,所以任务都是在切换执行,这就是所谓的任务调度。
线程是一个轻量级的子进程,是最小的处理单元。它时一个单独的执行路径。
线程是独立的,如果在一个线程中发生异常,则不会影响其他线程。它们共享进程的内存区域。
java多线程的优点
- 它不会阻塞用户,因为线程是独立的,可以同时执行多个操作。
- 可以一起执行许多操作,因此可以节省时间。
- 线程是独立的,因此如果在单个线程中发生异常,他不会影响其他线程。
- 可以有效的利用多cpu。
- 线程共享相同的地址空间。
- 线程是轻量级的。
- 线程之间的通信成本很低。
注:在单核cpu同一时间只是执行一个线程。
Java Thread类:
Java提供了Thread类来实现线程编程。
Java线程方法
编号 | 修辞符 | 方法 | 描述 |
1 | void | 它用于开始执行线程。 | |
2 | void | 它用于为线程执行操作。(重写此方法进行自己的逻辑) | |
3 | static void | 它会在指定的时间内休眠一个线程。 | |
4 | static Thread | 它返回对当前正在执行的线程对象的引用。 | |
5 | void | 它等待线程死亡 | |
6 | int | 它返回线程的优先级。 | |
7 | void | 它设置改变线程的优先级。 | |
8 | String | 它返回线程的名称。 | |
9 | void | 它用于设置线程的名称。 | |
10 | long | 它返回线程的编号(id)。 | |
11 | boolean | 它测试线程是否存活。 | |
12 | static void | 它使当前正在执行的线程对象暂停并允许其他线程临时执行。 | |
13 | void | 它用于挂起线程。 | |
14 | void | 它用于恢复挂起的线程。 | |
15 | void | 它用于停止线程。 | |
16 | void | 它用于销毁线程组及其所有子组。 | |
17 | boolean | 它测试该线程是否是一个守护程序线程。 | |
18 | void | 它将线程标记为守护程序或用户线程。 | |
19 | void | 它会中断线程。 | |
20 | boolean | 它测试线程是否被中断。 | |
21 | static boolean | 它测试当前线程是否已被中断。 | |
22 | static int | 它返回当前线程的线程组中活动线程的数量。 | |
23 | void | 它确定当前运行的线程是否具有修改线程的权限。 | |
24 | static boolean | 当且仅当当前线程在指定对象上保存监视器锁时,它才返回true。 | |
25 | static void | 它用于将当前线程的堆栈跟踪打印到标准错误流。 | |
26 | StackTraceElement[] | 它返回一个堆栈跟踪元素数组,表示线程的堆栈转储。 | |
27 | static int | 它用于将每个活动线程的线程组及其子组复制到指定的数组中。 | |
28 | Thread.State | 它用于返回线程的状态。 | |
29 | ThreadGroup | 它用于返回此线程所属的线程组 | |
30 | String | 它用于返回此线程的字符串表示形式,包括线程的名称,优先级和线程组。 | |
31 | void | 它仅用于为等待指定对象的一个线程发出通知。 | |
32 | void | 它用于向指定对象的所有等待线程发出通知。 | |
33 | void | 它为Thread设置上下文ClassLoader。 | |
34 | ClassLoader | 它返回线程的上下文ClassLoader。 | |
35 | static Thread.UncaughtExceptionHandler | 它返回由于未捕获的异常而导致线程突然终止时调用的默认处理程序。 | |
36 | static void | 它设置当线程由于未捕获的异常而突然终止时调用的默认处理程序。 |
线程的生命周期:
java中线程的生命周期由JVM控制:
- 初始:新创建了一个线程对象,但还没有调用start()方法。创建Thread类的实例但未调用start()方法,线程处于初始状态.
- 运行:Java线程中将就绪(ready)和运行中(running)两种状态笼统的称之为”运行“。线程对象创建后,其他线程(比如main)调用了该对象的statrt()。该状态的线程位于可运行线程池中,等待调度,获取cpu的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行状态(running)。
- 阻塞:表示线程阻塞于锁
- 等待:进入该状态的线程需要等待其他线程做出一些特定的动作(通知或中断)
- 超时等待:该状态不同于等待,他可以在指定的时间后自行返回.
- 终止:表示该线程已经执行完毕.
线程的创建与调度
创建线程的方法:
- 继承Thread类
- 实现Runnable接口
java中线程的执行体是线程中的run()方法,在run()方法中编写需要执行的任务代码逻辑,启动时进行并行执行。
两种线程启动方式的比较:
java是单继承的,继承的方式创建线程,将会占用了extends关键字,这在类本身需要继承其他类的情况下无法使用
java是多实现的,实现接口的数量没有线程,所以实现接口创建线程的方式并不会受到单继承的线程
线程调度算法:
抢占式调度算法和时间片调度算法.
在抢占式调度下,优先级最高的任务优先执行.无法保证线程调度程序选择到底哪个线程运行.(效率较高)
时间片调度,会执行一段时间进入任务就绪池.等待调度程序再次调度
Java能否两次启动同一线程?
不能,启动线程后,在当前线程未死亡时,不能再次启动.如果启动则抛出
IllegalThreadStateException
启动线程调用Thread的start()方法,而不是run
join()方法等待线程死亡。它会导致当前运行的线程停止执行,直到它加入的线程完成其任务。
当前线程
currentThread()方法返回当前正在执行的线程的引用。
java中默认有10个优先级。
守护线程
java中的守护线程是一个服务提供程序线程,它为用户线程提供服务。
它的生命依赖于用户线程,即当所有用户线程都死亡,JVM会自动终止该线程。
java守护线程举例:gc,finalizer
Thread类的Java守护程序线程的方法
java.lang.Thread类为java守护程序线程提供了两种方法。
编号 | 方法 | 描述 |
1 | public void setDaemon(boolean status) | 用于将当前线程标记为守护程序线程或用户线程。 |
2 | public boolean isDaemon() | 用于检查当前是守护进程。 |
注:如果要将用户线程设置为守护线程,则不能启动它,否则抛出
IllegalThreadStateException。
下一节,线程的并发问题