Java线程的几种创建方式有什么区别
继承Thread类
通过继承Thread类并重写run方法。适合快速创建简单的线程任务。缺点就是Java不支持多继承,如果你的类已经继承了另一个类,就不能再继承Thread。同时不适合复杂的线程管理和资源共享场景。
实现Runnable接口
通过实现Runnable接口并将其传递给Thread对象。适合需要共享资源或任务的场景。可以实现多个接口,增加了灵活性。多个线程可以共享同一个Runnable实例,方便资源共享和任务分配。
实现Callable接口和使用FutureTask
实现Callable接口来创建线程,并使用FutureTask来管理返回结果。适合需要返回结果的并发任务,可以返回任务执行结果。同时可以抛出异常,便于异常处理。相比Runnable,实现和使用稍微复杂一些。
使用线程池
通过ExecutorService来创建和管理线程池,适合需要管理大量线程的场景。减少了频繁创建和销毁线程的开销。更好地管理系统资源,防止资源耗尽。可以根据任务量动态调整线程池大小。
Java多线程优先级
在Java中,每个线程都有一个优先级,优先级决定了线程调度器对线程的调度顺序。线程的优先级是一个整数值,范围在1到10之间。
最低优先级:Thread.MIN_PRIORITY(值为1)
默认优先级:Thread.NORM_PRIORITY(值为5)
最高优先级:Thread.MAX_PRIORITY(值为10)
Java多线程的生命周期
在Java中,线程的生命周期包括多个状态,每个状态表示线程在其生命周期中的不同阶段。线程的生命周期状态主要包括:
- 新建(New)
- 就绪(Runnable)
- 运行(Running)
- 阻塞(Blocked)
- 等待(Waiting)
- 超时等待(Timed Waiting)
- 终止(Terminated)
线程的基本方法
start()
start()方法用于启动线程。线程创建以后,并不会自动运行,需要我们调用start(),将线程的状态设为就绪状态,但不一定马上就被运行,得等到CPU分配时间片以后,才会运行
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running");
}
}
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // 启动新线程
}
}
注意:直接调用run()方法不会启动新线程,而是在当前线程中执行run()方法。
run()
run()方法包含线程执行的代码。它是Thread类和Runnable接口的核心方法。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running");
}
}
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start(); // 启动新线程,实际调用的仍是 run() 方法
}
}
sleep(long millis)
sleep(long millis)方法使当前线程休眠指定的毫秒数。它会抛出InterruptedException,因此需要处理该异常。
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
System.out.println("Thread is sleeping");
Thread.sleep(1000); // 休眠1秒
System.out.println("Thread woke up");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
}
}
join()
join()方法等待线程终止。调用该方法的线程会等待被调用线程执行完毕后再继续执行。
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
Thread.sleep(1000); // 模拟工作
System.out.println("Thread finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
try {
t1.join(); // 等待 t1 线程结束
System.out.println("Main thread continues");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Java线程池的原理
Java线程池是一种管理和复用线程的机制,旨在提高应用程序的性能和资源利用效率。线程池通过减少线程创建和销毁的开销来提高系统的响应速度和吞吐量,并且可以有效管理和控制线程的数量,防止过多的线程导致系统资源耗尽。
线程池的基本原理
- 线程复用:线程池在初始化时创建一定数量的线程,这些线程在任务执行完毕后不会被销毁,而是被回收并重新用于执行新的任务。
- 任务队列:当所有线程都在忙碌时,新提交的任务会被放入任务队列中,等待空闲线程来执行。
- 线程管理:线程池可以根据需要动态调整线程的数量,创建新线程或销毁空闲线程,以应对任务量的变化。
- 资源控制:通过限制线程的数量,线程池可以防止系统资源(如CPU、内存)被过度消耗。