简介
线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(Lightweight Process,LWP),但一般不称呼线程为进程。线程几乎不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
线程可以使得程序中的每个部分都能并发地执行。多线程意味着一个应用程序的多个部分可以同时执行,进而提高了应用程序的执行效率。多线程是在同一时间执行多个任务,使得CPU的利用率最大化。
多线程编程的主要优势包括:
- 资源共享:线程共享其所属进程的地址空间和其他资源,这使得线程间的通信更加高效。
- 经济性:线程创建和销毁的开销比进程小得多,因此可以创建大量的线程而不会占用太多系统资源。
- 并发执行:多线程允许程序中的多个部分同时执行,提高了程序的执行效率。
然而,多线程编程也带来了一些挑战,如线程同步和数据一致性问题
Thread
直接继承Thread类,重写run()方法定义线程要执行的任务
public class ThreadTest extends Thread{
@Override
public void run() {
// 这里编写线程需要执行的任务
System.out.println("线程"+ currentThread().getName()+"正在执行");
}
public static void main(String[] args) {
ThreadTest test = new ThreadTest();
//启动线程
test.start();
}
}
优点
- 实现起来相对简单明了
- 直接拥有线程的方法和属性,如获取线程名、设置优先级等
缺点
- 由于Java不允许多继承,如果继承了Thread就无法继承其它类
- 当需要处理大量任务时,这种方式会导致类数量过多,不利于维护和扩展
Runnable
实现Runnable接口,重写run()方法定义线程要执行的任务。然后将这个类作为实例传递给Thread
public class RunnableTest implements Runnable{
@Override
public void run() {
System.out.println("线程"+ Thread.currentThread().getName()+"正在执行");
}
public static void main(String[] args) {
RunnableTest runnableTest = new RunnableTest();
//将当前类作为实例传递给Thread
Thread thread = new Thread(runnableTest);
//启动线程
thread.start();
}
}
优点
- 允许任务类与线程分离,更容易进行单元测试和重构
- 可以让一个类同时实现多个接口,避免了单继承带来的局限性
- 方便任务复用,同一个
Runnable
对象可以被多个线程共享
缺点
- 不直接拥有
Thread
类中的控制方法,如果需要访问或修改线程状态,需要额外持有对Thread
对象的引用
Callable、FutureTask
实现Callable接口,重写call()方法定义线程要执行的任务,可以返回值,数据类型为Object。然后通过FutureTask或ExecutorService创建并管理线程
public class CallableTest implements Callable {
@Override
public Object call() throws Exception {
System.out.println("线程"+ Thread.currentThread().getName()+"正在执行");
return "callable返回值";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask task = new FutureTask(new CallableTest());
Thread thread = new Thread(task);
thread.start();
//call返回值
System.out.println(task.get());
}
}
优点
- 支持返回值,类型为Object
- 结合 ExecutorService提供了更强大的线程管理和异步计算功能
缺点
- 操作相对复杂,涉及到线程池的概念和更多高级API的使用
总结
以上四种方式均是Java中常用的线程创建方法,每种方式都有其适用场景,开发者可以根据项目的具体需求和设计原则来选择最适合的创建方式。直接创建线程适用于轻量级并发任务或者临时性的任务处理,而线程池更适合于处理大量的短生命周期任务,能够有效提高系统的整体性能和响应速度。在实际开发中,我们通常推荐使用线程池来管理并发任务,因为它能更好地平衡系统资源利用率与任务执行效率。