现在几乎所有操作系统都支持多任务执行,其中每个任务被视为一个进程。在每个进程内部,至少有一个线程在运行,线程也被称为轻量级进程。
线程可以看作是程序执行的一条路径,每个线程都有自己的局部变量表、程序计数器(指向当前正在执行的指令)以及各自的生命周期。现代操作系统通常支持同时运行多个线程。例如,在启动Java虚拟机(JVM)时,操作系统会创建一个新的进程(即JVM进程),并在该进程中生成多个派生或创建的线程。
在JDK17版本的JVM线程的生命周期共7个状态,可以在java.lang.Thread.State
枚举类看到,具体如下:
这些线程状态在Java中非常重要,理解它们的含义和转换规则有助于我们编写高效、正确的多线程程序。
线程的生命周期是从新建状态开始,通过调用 start() 方法进入可运行状态,然后可能进入阻塞、等待或者被中断,最后进入终止状态。JVM 管理线程状态的转换,可以通过 Thread 类的状态相关方法来查询当前线程的状态。
创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元则有两种方式。
public class MyThread extends Thread {
public void run() {
// 定义线程执行的任务
System.out.println("This is a new thread.");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start(); // 启动线程
}
}
public class MyRunnable implements Runnable {
public void run() {
// 定义线程执行的任务
System.out.println("This is a new thread.");
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable); // 将实现了 Runnable 接口的对象作为参数传递给 Thread 类的构造方法
thread.start(); // 启动线程
}
}
无论是 Runnable 接口的 run() 方法,还是 Thread 类本身的 run() 方法,都遵循了将线程的控制逻辑与业务逻辑分离的原则,以实现职责分明、功能单一的设计思想。这种设计方式与 GoF(Gang of Four)设计模式中的策略模式有相似之处。
在策略模式中,将可变的算法封装成独立的策略类,并通过接口或抽象类与调用者进行解耦。调用者可以根据需要选择不同的策略来完成特定的任务。类似地,Java 中的线程创建方式也将线程的执行逻辑封装在一个单独的类(实现 Runnable 接口或继承 Thread 类)中,通过调用 start() 方法来启动线程。
使用这种设计模式,可以使线程控制逻辑与业务逻辑分离,提高代码的可维护性和可扩展性。例如,可以根据不同的业务需求,定义不同的 Runnable 实现类或 Thread 子类,并在启动线程时选择合适的线程对象,从而实现不同的业务逻辑。
总结来说,Java 中线程的创建方式与策略设计模式相似,都体现了将控制逻辑与具体业务逻辑分离的设计原则,以实现代码的灵活性和可扩展性。
重写 Thread 类的 run() 方法和实现 Runnable 接口的 run() 方法有一个关键的不同点。Thread 类的 run() 方法是无法共享的,也就是说,一个线程的 run() 方法不能被另一个线程当作自己的执行单元。相比之下,使用 Runnable 接口可以实现线程执行单元的共享。通过传递同一个实现了 Runnable 接口的对象给多个 Thread 实例,可以使多个线程共享同一个执行单元,从而提高代码的复用性和可维护性。
public class MyRunnable implements Runnable {
public void run() {
// 定义线程执行的任务
System.out.println("This is a new thread.");
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start(); // 启动线程
Thread thread2 = new Thread(myRunnable);
thread2.start(); // 启动线程
}
}
package engineer.concurrent.battle.onebasic;
import java.util.concurrent.TimeUnit;
public class TryConcurrent {
public static void main(String[] args) {
new Thread(TryConcurrent::writeCode).start();
listenMusic();
}
private static void listenMusic() {
for(;;){
System.out.println("music is good");
sleep(1);
}
}
private static void writeCode() {
for(;;){
System.out.println("write code and work hard");
sleep(1);
}
}
private static void sleep(int i) {
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 叫号机排队模拟,通过多线程并发
*/
public class TicketWindow extends Thread {
private final String name;
private final static int MAX = 100;
private static AtomicInteger index = new AtomicInteger(1);
public TicketWindow(String name) {
this.name = name;
}
public void run() {
while (index.get() <= MAX) {
System.out.println(name + "柜台正在排队,排队号码为:" + index);
index.getAndIncrement();
}
}
public static void main(String[] args) {
new TicketWindow("一号窗口").start();
new TicketWindow("二号窗口").start();
new TicketWindow("三号窗口").start();
new TicketWindow("四号窗口").start();
}
}