线程
线程的基本概念
并行和并发
- 并行:多个CPU核心同时工作,处理不同的任务。
- 并发:多个任务交替使用 CPU 核心工作,以提高 CPU 利用率。
进程和线程
进程 Processor
程序的一次执行。由操作系统创建并分配资源,执行一个单独的任务。
进程是系统进行资源分配和调度的独立单位,每个进程都有自己的内存空间和系统资源。进程内所有线程共享堆存储空间,保存程序中定义的对象和常量池。
Windows系统中,每个运行的 Java 程序都是一个独立的进程。
线程 Thread
进程内的执行单元,不分配单独的资源,执行一个单独的子任务。
线程是进程内调度和分派的基本单位,共享进程资源。每个线程有自己的独立的栈存储空间,保存线程执行的方法以及基本类型的数据。
运行的 Java 程序内含至少一个主线程 main ,用户可以在 Java 程序中自定义并调用多个线程。 JVM 垃圾回收线程也是一个独立的线程。
线程的运行状态
线程除创建状态 New 和结束状态 Terminate 外,主要有以下几种运行状态:
运行
(Running) CPU 正在执行线程。
就绪
(Runnable) 线程一切就绪,等待 CPU 执行。
运行/就绪状态 统称为可运行状态 Runnable。 Java 程序中,线程在 运行/就绪状态 之间的切换由 JVM 自动调度,开发者无法获知。线程之间的调度采用分优先级多队列时间片轮转算法。进程在执行完 CPU 时间片切换到就绪状态之前会先保存自己的状态,下次进入运行状态时再重新加载。
阻塞
(Blocked) 线程因缺少其他资源,比如请求资源被上锁而暂停执行。在获得资源后进入就绪状态。
等待
(Waitting) 线程接受了等待指令,释放资源暂停执行。在超时/接受唤醒指令后进入就绪状态。
Thread 类
Thread 类是系统自带的线程类,实现了 Runnable 接口。
线程定义
Runnable 接口内唯一声明了 run 方法,由 Thread 类实现。开发者在 run 方法中定义运行时线程将要执行的功能,线程开启后由 JVM 自动调用并执行。如果开发者主动调用 run 方法,只会当作普通方法执行。
开发者可以通过以下两种方式自定义线程类:
- 继承 Thread 类,重写 run 方法。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}Copy to clipboardErrorCopied
- 实现 Runnable 接口,实现 run 方法。推荐使用,避免了单继承的局限性。
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}Copy to clipboardErrorCopied
线程启动
Thread 类定义了 start 方法。调用 start 方法后,系统会开启一个新线程进入就绪状态:由 JVM 会自动对线程进行调度,在运行时调用并执行线程的 run 方法。一个线程只能启动一次。
- 如果自定义线程类继承 Thread 类,直接启动。
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread("ThreadName");
t1.start();
t2.start();
}
}Copy to clipboardErrorCopied
- 如果自定义线程类实现 Runnable 接口,则需要借助 Thread 类启动线程。
public class Main {
public static void main(String[] args) {
MyThread mythread = new MyThread();
Thread t1 = new Thread(mythread); // 由系统指定默认线程名 Thread-X
Thread t2 = new Thread(mythread, "ThreadName"); // 开发者自定义线程名
t1.start();
t2.start();
}
}Copy to clipboardErrorCopied
同时定义和启动线程
通过匿名内部类方式,我们可以实现同时定义和启动线程的简洁写法。
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable(){
public void run(){
System.out.println(Thread.currentThread().getName());
}
}).start();
}
}
// Lambda 表达式简写一
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}).start();
}
}
// Lambda 表达式简写二
public class Main {
public static void main(String[] args) {
Test test = new test();
Thread t = new Thread(test::method);
t.start();
}
}
class Test {
public void method() {
System.out.println(Thread.currentThread().getName());
}
}Copy to clipboardErrorCopied