线程
1.什么是线程
线程(Thread)是计算机科学中的基本概念,用于描述一个程序内部的执行路径。一个线程可以被看作是一个程序内部的独立执行流,能够单独执行代码,并与其他线程共享同一进程的资源。以下是关于线程的一些详细信息:
- 线程的特点:
- 轻量级:线程是比进程更小的执行单位。一个进程中可以包含多个线程,每个线程相对独立而且占用的资源较少。
- 并发执行:多个线程可以并发执行,各自独立地执行自己的任务,可以实现多任务处理。
- 共享内存:同一进程内的线程共享该进程的内存资源,因此可以直接访问共享变量,但也因此需要考虑线程安全性问题。
- 线程的创建:
- 在Java中,可以通过继承Thread类或实现Runnable接口来创建线程。
- 继承Thread类需要重写run()方法,然后创建Thread的实例并调用start()方法来启动线程。
- 实现Runnable接口需要实现run()方法,然后创建Thread的实例并将实现了Runnable接口的对象作为参数传递给Thread的构造函数来启动线程。
- 线程的生命周期:
- 线程在执行过程中会经历不同的状态,如新建、就绪、运行、阻塞和终止等状态。
- 线程的生命周期可以通过Thread类的方法来管理和控制,比如start()方法用于启动线程,sleep()和wait()方法用于使线程休眠或等待,join()方法用于等待一个线程执行完成。
- 线程调度:
- 线程调度是操作系统或虚拟机对多个线程之间的执行顺序进行管理和调度的过程。
- 线程调度策略包括抢占式调度和协作式调度,在不同的操作系统和编程环境中可能有不同的调度策略。
- 线程同步与线程安全:
- 多个线程访问共享数据时会引发竞争条件和数据不一致的问题,因此需要通过同步机制来确保多线程安全访问共享资源。
- Java提供了synchronized关键字、Lock对象、volatile关键字等机制来实现线程同步,以避免多线程并发访问导致的问题。
线程是并发编程中非常重要的概念,合理使用线程可以充分利用多核处理器的性能优势,提高程序的性能和响应速度。然而,需要注意线程间的协作、同步和安全性问题,以避免因为多线程访问共享资源而导致的意外结果。
2.创建线程的方式
在Java中,有两种主要的方式来创建线程:
1.通过继承Thread类:
- 创建一个继承自Thread类的子类,重写子类的run()方法来定义线程要执行的任务。
- 实例化子类的对象,并调用start()方法来启动线程的执行。
public class MyThread extends Thread {
public void run() {
// 定义线程要执行的任务
System.out.println("Thread is running");
}
}
// 启动线程
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
2.通过实现Runnable接口:
- 创建一个实现了Runnable接口的类,实现接口中的run()方法来定义线程要执行的任务。
- 创建Thread对象,将实现了Runnable接口的类的实例作为参数传递给Thread的构造函数,并调用start()方法来启动线程的执行。
public class MyRunnable implements Runnable {
public void run() {
// 定义线程要执行的任务
System.out.println("Runnable is running");
}
}
// 启动线程
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
这两种方式都可以用来创建线程,但一般推荐使用实现Runnable接口的方式,因为Java不支持多重继承,而实现接口可以更灵活地扩展其他类。另外,通过实现Runnable接口还能更好地描述任务和线程之间的关系,使代码更清晰和易于维护。
在Java中,除了通过继承Thread类或实现Runnable接口来创建线程外,还可以使用Callable接口来创建线程。Callable接口是一个泛型接口,可以返回线程执行结果,并且可以抛出异常。与Runnable接口不同的是,Callable接口的call()方法可以有返回值。
下面是使用Callable接口创建线程的步骤:
- 创建一个实现Callable接口的类,并实现call()方法来定义线程要执行的任务。
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
public String call() throws Exception {
// 定义线程要执行的任务
return "Callable is running";
}
}
2.使用Executor框架来启动Callable任务。Executor框架是Java并发编程中用来管理线程的工具,可以在程序中方便地提交和执行线程任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) {
MyCallable myCallable = new MyCallable();
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(1);
// 提交Callable任务并获取Future对象
Future<String> future = executor.submit(myCallable);
try {
// 获取线程执行结果
String result = future.get();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
// 关闭线程池
executor.shutdown();
}
}
在上面的示例中,我们首先创建了一个实现Callable接口的类MyCallable,然后通过Executor框架创建了一个线程池并提交了Callable任务。最后通过Future对象获取线程的执行结果。
使用Callable接口创建线程可以更方便地获取线程的执行结果,并且可以更灵活地处理异常。相比于Runnable接口,Callable接口更适合一些需要返回结果的线程任务场景。
3.Thread类中常用的方法
在Java中,Thread类提供了许多常用的方法来操作线程。以下是Thread类中常用的一些方法:
- start():
- 通过调用start()方法来启动线程,使其进入就绪状态,等待CPU调度执行。
- run():
- 在Thread类中,run()方法定义了线程的执行逻辑。
- sleep(long millis):
- 让当前线程休眠指定的时间(以毫秒为单位)。
- join():
- 等待调用join()方法的线程执行完成后,当前线程再继续执行。
- join(long millis):
- 等待调用join()方法的线程执行完成,最多等待millis毫秒。
- interrupt():
- 中断线程,将线程的中断标记设置为true。
- isInterrupted():
- 判断线程是否被中断。
- getName():
- 获取线程的名称。
- setName(String name):
- 设置线程的名称。
- yield():
- 让出CPU执行权,给其他线程执行机会。
- isAlive():
- 判断线程是否还存活。
- setPriority(int priority):
- 设置线程的优先级。
- getPriority():
- 获取线程的优先级。
- wait():
- 当前线程进入等待状态,直到另一个线程调用notify()或notifyAll()方法唤醒它。
- notify() / notifyAll():
- 唤醒正在等待的线程。
这些是Thread类中的一些常用方法,可以帮助我们操作线程的状态和行为。根据具体的需求,我们可以选择合适的方法来控制线程的执行。
4.Runable和Callable的区别
标签:基本,Runnable,Thread,接口,Callable,线程,使用,执行 From: https://www.cnblogs.com/lsran/p/18283717在Java中,Runnable和Callable接口都可以用来创建多线程,但它们之间有一些区别:
- 返回值:
- Runnable接口中的run()方法没有返回值,而Callable接口中的call()方法可以返回一个结果。
- 异常处理:
- Runnable接口中的run()方法不能抛出已检查异常,但可以通过try-catch在方法内部处理异常;而Callable接口的call()方法可以抛出异常,需要通过捕获或声明抛出来处理异常。
- 返回结果:
- Callable接口可以返回一个结果,而Runnable接口无法直接返回结果,但可以通过共享变量或其他方式来获取线程执行结果。
- Future类:
- 在使用Callable接口时,可以通过Future来获取线程执行的结果,而Runnable接口没有提供类似的机制。
- 适用场景:
- Callable适用于需要返回结果、可能抛出异常的线程任务;而Runnable适用于简单的无需返回结果、不会抛出异常的线程任务。
总的来说,如果需要线程执行任务后返回一个结果或者抛出异常,可以使用Callable接口;如果只是简单的执行任务而不需要返回结果,可以使用Runnable接口。根据具体需求,选择适合的接口来创建线程可以使代码更加清晰和方便处理线程任务的结果