目录
概述
一. 继承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{
@Override
public 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() {
@Override
public 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() {
@Override
public 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> { @Override public 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(); } } }