目录
继承Thread类
- 创建一个继承自Thread类的子类,并重写其run()方法,将相关逻辑实现,run()方法就是线程要执行的业务逻辑方法。
- 创建自定义的线程子类对象
- 调用子类实例的star()方法来启动线程
为了更好地理解单线程和多线程的执行过程,接下来通过一个图例分析一下单线程和多线程的区别。
从上图可以看出,单线程的程序在运行时,会按照代码的调用顺序执行,而在多线程中,main()方法和MyThread类的run()方法却可以同时运行,互不影响,这正是单线程和多线程的区别。
示例代码如下:
class MyThread extends Thread {
public void run() {
// 线程执行的代码逻辑
System.out.println(Thread.currentThread().getName() +"线程正在运行");
}
}
public class Main {
public static void main(String[] args) {
// 创建线程并启动
MyThread thread = new MyThread();
thread.start();
System.out.println(Thread.currentThread().getName() + " main()方法执行结束");
}
}
运行结果:
main main()方法执行结束
Thread-0线程正在运行
扩展小知识:
Thread类的常见方法
- start(): 启动线程,并使其进入可运行状态,当CPU调度到该线程时,会自动调用其run()方法开始执行线程代码。
- run(): 线程的执行逻辑,通常需要在子类中重写该方法以定义具体的线程行为。通过调用start()方法来启动线程时,系统会自动调用该方法。
- sleep(long millis): 让当前线程暂停执行指定的时间(以毫秒为单位),进入阻塞状态。暂停期间不占用CPU时间,其他线程可以继续执行。
- join(): 当一个线程A调用另一个线程B的join()方法时,线程A将会等待线程B执行完毕后才继续执行。
- holdsLock(Object x):当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
- dumpStack():将当前线程的堆栈跟踪打印至标准错误流。
- getName(): 获取线程的名称。
- setName(String name): 设置线程的名称。
- getId(): 获取线程的唯一标识符。
- isAlive(): 判断线程是否存活,即线程是否已启动但尚未终止。
- setPriority(int priority): 设置线程的优先级,优先级范围为1-10,默认为5。优先级较高的线程在竞争资源时有更大的概率优先执行。
- yield(): 暂停当前正在执行的线程,并让出CPU资源给其他具有相同优先级的线程。仅是一种建议,不保证有效,具体是否产生效果取决于系统的调度器。
- interrupt(): 中断线程,给线程发送中断信号。线程在合适的时候可以检查到该中断请求,然后自行决定如何响应。
- isInterrupted(): 判断线程是否被中断,返回布尔值。
- static boolean interrupted(): 判断当前线程是否被中断,并清除中断状态。
Thread 类的静态方法
currentThread() 是 Thread 类的静态方法,它返回当前正在执行的线程对象。具体来说,它返回一个表示当前线程的 Thread 对象。
可以使用 Thread.currentThread() 来获取当前线程的引用。这个方法常用于需要获得当前执行线程对象的场景,例如需要在运行时获取线程的名称、线程优先级、判断线程是否被中断等操作。
注意:currentThread() 是 Thread 类的静态方法,因此可以直接通过 Thread.currentThread() 的方式调用,不需要创建 Thread 对象实例。
下面是一个示例代码,演示如何使用 currentThread() 方法:
public class Main {
public static void main(String[] args) {
// 获取当前线程对象
Thread currentThread = Thread.currentThread();
// 获取当前线程的名称
String threadName = currentThread.getName();
System.out.println("当前线程名称:" + threadName);//当前线程名称:main
// 获取当前线程的优先级
int threadPriority = currentThread.getPriority();
System.out.println("当前线程优先级:" + threadPriority);//当前线程优先级:5
// 判断当前线程是否被中断
boolean isInterrupted = currentThread.interrupted();
System.out.println("当前线程是否被中断:" + isInterrupted);//当前线程是否被中断:false
}
}
注意:getPriority() 方法是 Thread 类的实例方法,用于获取线程的优先级。该方法返回一个表示线程优先级的整数值。
线程优先级的范围是从 1 到 10,默认优先级为 5。较大的优先级值意味着线程更重要或更紧急,但并不保证高优先级的线程总是比低优先级的线程先执行。
实现Runnable接口
- 创建一个类实现Runnable接口,并重写其run()方法。
- 然后创建Thread对象,并将该实现Runnable接口的类的实例作为参数传递给Thread构造函数。
- 最后调用Thread对象的start()方法启动线程。
注意,实现 Runnable 接口相比直接继承 Thread 类具有更好的灵活性和可扩展性,因为它允许多个线程共享相同的 Runnable 实例。
下面是一个实现 Runnable 接口的示例代码:
class MyRunnable implements Runnable {
@Override
public void run() {
// 在此处添加想要线程执行的代码逻辑
System.out.println("线程运行中");
}
}
public class Main {
public static void main(String[] args) {
// 创建 MyRunnable 实例
MyRunnable myRunnable = new MyRunnable();
// 创建 Thread 对象并传入 MyRunnable 实例
Thread thread = new Thread(myRunnable);
// 启动线程
thread.start();
}
}
使用Callable和Future创建线程
- 创建一个实现Callable接口的类,并重写其call()方法。
- 然后使用ExecutorService提交Callable任务,并通过Future对象获取返回结果。
注意:使用 Callable 和 Future 创建线程相比直接使用 Runnable 接口和 Thread 类更为灵活,因为它允许获得线程的执行结果,并能够异步地处理任务。
下面是使用 Callable 和 Future 创建线程的示例代码:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main implements Callable<String> {
@Override
public String call() {
// 在此处添加想要线程执行的代码逻辑
return "线程运行结束";
}
public static void main(String[] args) throws Exception {
// 创建 CallableExample 实例
Main callableExample = new Main();
// 创建线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交 CallableExample 实例到线程池并返回 Future 对象
Future<String> future = executor.submit(callableExample);
// 关闭线程池(可选)
executor.shutdown();
// 获取线程执行结果
String result = future.get();
System.out.println("线程结果: " + result);//线程结果: 线程运行结束
}
}
使用Executor框架创建线程池
Executors提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
主要有newFixedThreadPool,newCachedThreadPool,newSingleThreadExecutor,newScheduledThreadPool。
注意,调用 shutdown() 方法后,线程池将不再接受新的任务,并且会等待已提交的任务执行完成。
使用 Executor 框架可以更方便地管理和控制线程池,避免手动创建和启动线程的繁琐操作。
下面是使用 Executor 框架创建线程池的示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
// 创建固定大小的线程池,最多同时执行两个线程
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交任务到线程池
executor.submit(new MyTask("任务1"));
executor.submit(new MyTask("任务2"));
executor.submit(new MyTask("任务3"));
// 关闭线程池
executor.shutdown();
}
static class MyTask implements Runnable {
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("任务 " + name + " 正在执行");
}
}
}
执行结果
任务 任务2 正在执行
任务 任务1 正在执行
任务 任务3 正在执行