目录
概述
一. 继承Thread类
1. 特点
2. 注意事项
3. 代码示例
二. 实现Runnable接口
1. 特点
2. 注意事项
3. 代码示例
三. 实现Callable接口
1. 特点
2. 注意事项
3. 代码示例
概述
在Java中,线程(Thread)是程序执行的最小单元,它允许程序在同一时间执行多个任务。Java中的线程可以由Thread类创建,也可以通过实现Runnable接口或Callable接口创建。
java中线程几种状态:
新建(New): 线程对象已经被创建,但还没有调用
start()
方法。可运行(Runnable): 线程已经调用了
start()
方法,但还没有获得CPU时间片执行。可运行状态包括了操作系统线程的就绪(Ready)和运行(Running)状态。阻塞(Blocked): 线程因为等待监视器锁而被阻塞,无法继续执行。
等待(Waiting): 线程通过调用
wait()
、join()
、LockSupport.park()
等方法进入等待状态,需要其他线程通知或中断后才可能继续执行。超时等待(Timed Waiting): 线程通过调用带有超时参数的
sleep()
、wait()
、join()
、LockSupport.parkNanos()
、LockSupport.parkUntil()
等方法进入超时等待状态,超时后会自动唤醒。终止(Terminated): 线程的
run()
方法执行结束,或者因异常退出了run()
方法。线程的状态枚举类 State
一. 继承Thread类
通过继承Thread类并重写run方法来创建线程,本质上继承Thread类实现线程的方式也是通过实现 Runnable 接口,
1. 特点
- 简单性:实现线程的代码简单直观。
- 局限性:由于Java的单继承特性,如果一个类已经继承了其他类,就不能再继承
Thread
类。
2. 注意事项
- 不要调用
Thread
类的run
方法:应该重写run
方法,而不是直接调用它。 - 使用
start
方法启动线程:start
方法会创建一个新的线程,并调用run
方法。 - 线程安全:如果线程之间需要共享数据,需要考虑线程安全问题。
3. 代码示例
package com.demo.thread;/*** 文件名:ThreadDemo* 创建者:* 创建时间:2024-09-22* 描述: 通过继承 Thread 类并重写run方法来创建线程*/
public class ThreadDemo extends Thread{@Overridepublic void run(){System.out.println(Thread.currentThread().getName()+"-执行run方法");}
}/*** 测试类*/
class MainThread{public static void main(String[] args) {//1.第一种方式创建线程Thread thread = new Thread(new ThreadDemo(),"线程1");thread.start(); //启动线程//2.第二种方式创建线程Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"-执行run方法");}},"线程2");thread2.start(); //启动线程}
}
二. 实现Runnable接口
实现 Runnable
接口是Java中创建线程的另一种常见方式,这种方式更加灵活,因为它允许类继承其他类的同时实现线程功能。Runnable
接口定义了一个 run
方法,这是线程执行的入口点。
1. 特点
- 灵活性:实现
Runnable
接口允许类继承其他类,同时实现多线程功能。 - 线程安全:如果多个线程共享同一个
Runnable
实例,需要考虑线程安全问题。
2. 注意事项
- 不要在
run
方法中调用Thread.currentThread().stop()
:这是不推荐的做法,因为它可能会导致程序处于不确定状态。 - 异常处理:在
run
方法中妥善处理异常,避免线程意外终止。 - 资源清理:如果线程使用了一些资源(如文件句柄、数据库连接等),确保在线程结束时释放这些资源。
3. 代码示例
package com.demo.thread;/*** 文件名:RunnableDemo* 创建者:* 创建时间:2024-09-22* 描述:实现 Runnable接口创建线程*/
public class RunnableDemo implements Runnable{public void run() {System.out.println(Thread.currentThread().getName()+"-"+"执行run方法");}
}/*** 测试类*/
class MainDemo{public static void main(String[] args) {//1.第一种创建线程执行Thread thread = new Thread(new RunnableDemo(),"线程1");thread.start(); // 启动线程//2.第二种创建线程执行Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"-执行run方法");}},"线程2");thread2.start(); // 启动线程}
}
三. 实现Callable接口
当我们需要创建一个可以返回结果的线程时,就可以使用实现了Callable接口的方式。Callable接口是在Java 5中引入的,它允许线程执行一个任务并返回一个结果,与Runnable接口相比,Callable接口的call()方法可以返回结果并抛出异常。
Callable
接口与 Runnable
接口类似,但它可以返回一个结果并且能抛出异常。Callable
通常与 FutureTask
一起使用,后者实现了 Runnable
接口,并且包装了 Callable
对象。
1. 特点
- 返回结果:
Callable
任务可以返回一个结果,可以通过FutureTask.get()
方法获取。 - 抛出异常:
Callable
任务可以抛出异常,可以通过FutureTask.get()
方法捕获。
2. 注意事项
- 异常处理:在
call
方法中抛出的异常可以通过FutureTask.get()
方法的调用者捕获。 - 线程安全:如果
Callable
任务需要访问共享资源,需要考虑线程安全问题。
3. 代码示例
使用步骤:
- 创建一个实现
Callable
接口的类。- 实现
Callable
接口的call
方法,该方法是线程执行的入口点。- 创建
Callable
实例。- 将
Callable
实例传递给FutureTask
的构造器。- 将
FutureTask
对象传递给Thread
类的构造器。- 创建
Thread
对象。- 调用
Thread
对象的start
方法来启动线程。
- 简单使用
package com.demo.thread;import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;/*** 文件名:CallableDemo* 创建者:* 创建时间:2024-09-22* 描述:通过 Callable 接口实现线程创建*/ public class CallableDemo implements Callable<String> {@Overridepublic String call() throws Exception {return "测试";} }/*** 测试类*/ class MainCallable{public static void main(String[] args){//1.创建对象CallableDemo demo = new CallableDemo();FutureTask<String> futureTask = new FutureTask<>(demo);//2.创建线程Thread thread = new Thread(futureTask);thread.start();//3.获取返回结果String res;try {res = futureTask.get();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}System.out.println("获取线程返回结果:"+res);} }
- 通过线程池使用
package com.demo.thread;import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;/*** 文件名:Main* 创建者:* 创建时间:2024-09-22* 描述:*/ public class Main {public static void main(String[] args) {//1.创建一个线程池ExecutorService executorService = Executors.newSingleThreadExecutor();//2.创建Callable任务Callable<String> callableTask = () -> {Thread.sleep(2000); // 模拟长时间运行的任务return "测试";};//3.提交Callable任务并获取Future对象Future<String> future = executorService.submit(callableTask);try {//3.获取异步任务的执行结果String result = future.get(); //此方法会阻塞,直到任务执行完成System.out.println("任务执行结果: " + result);} catch (Exception e) {e.printStackTrace();} finally {//4.关闭线程池executorService.shutdown();}} }