1 继承Thread类
Thread类是java.lang包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread实例。Thread类中常用的两个构造方法如下:
public Thread():创建一个新的线程对象。
public thread(String threadName):创建一个名称为threadName的线程对象。
public class ThreadTest extends Thread{
}
完成线程真正功能的代码放在类的run()方法中,当一个类继承Thread类后,就可以在该类中覆盖run()方法,将实现该线程功能的代码写入run()方法中,然后同时调用Thread类中的start()方法执行线程,也就是调用run()方法。
Thread对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run()方法中。
public void run(){
}
如果start()方法调用一个已经启动的线程,系统抛出IlleagalThreadStataException异常。
public static void main(String[] args) {
Thread t = new Thread(() ->{
});
t.start();
t.start();
}
当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该线程就为单线程程序,主方法线程启动就由Java虚拟机负责,程序员负责启动自己的线程。
public static void main(String[] args) {
new ThreadTest().start();
}
下面来看一个继承Thread类的实例。
package thread;
class Mythread extends Thread{ //指定类继承Thread类
public void run(){ //重写run方法
while (true) {
System.out.println("hello thread"); //打印
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class demo1 {
public static void main(String[] args) {
Mythread t = new Mythread();
//创建线程
t.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行本实例,结果如下所示:
在上述实例中,继承了Thread类,然后在类中覆盖了run()方法。通常在run()方法中使用无限循环的形式,使得线程一直运行下去,所以要制定一个跳出循环的条件,比如break或者return。
在main方法中,使线程执行需要调用Thread中的start()方法,start()方法调用被覆盖的run()方法,如果不调用start()方法,线程永远不会启动,在主方法没有调用start()方法之前,Thread对象只是一个实例,而不是一个真正的线程。
2 实现Runnable接口
目前为止,线程都是通过扩展Thread类来创建的,如果我们需要继承其他类(非Thread类),而且还要使得当前类实现多线程,那么可以通过Runnable接口来实现。
public class Thread extends Object implements Runnable
如果我们查询API,从中可以发现,实质上Thread类实现了Runnable接口,其中的run()方法正是对Runnable接口中的run()方法的具体实现。
使用Runnable接口启动新的线程的步骤如下:
1 建立Runnable对象。
public class MyRunnable implements Runnable {
@Override
public void run() {
// 这里是线程要执行的具体代码
System.out.println("Runnable thread is running...");
}
}
2 使用参数为Runnable对象的构造方法创建Thread实例。
Thread myThread = new Thread(new MyRunnable());
3 调用start()方法启动线程。
myThread.start();
3 实现Callable接口
Callable接口是Java并发编程中的一部分,它在包中定义,用于创建可执行的任务。Callable接口不仅提供了像Runnable那样的方法来执行任务,还允许你为任务返回一个结果。这使得Callable非常适合那些需要返回值或者抛出异常的异步操作。
当你实现Callable接口时,你需要:
1.实现call()方法:这是一个泛型方法,通常返回一个类型化的结果。例如,如果你的任务是计算两个数的和,你可以返回类型的结果。
public class SumCalculator implements Callable<Integer> {
private int a, b;
public SumCalculator(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public Integer call() throws Exception {
return a + b;
}
}
2.使用Future和ExecutorService:一旦创建了Callable任务,你可以将它提交给SumCalculator,然后使用来获取结果或者检查执行状态。如果方法抛出异常,会捕获并封装这些异常。
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new SumCalculator(10, 20));
try {
int result = future.get(); // 等待结果
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
4 通过线程池创建线程
线程池(Thread Pool)是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。Java 的 ExecutorService 提供了这样的线程池机制,但在非 Java 语言或环境下,如 Python,线程池的创建和使用会有所不同。
在JAVA中,我们可以使用Executors类来创建线程池:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
// 提交任务到线程池
executor.execute(worker);
}
// 关闭线程池
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("所有线程执行完毕");
}
static class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 开始执行命令: " + command);
processCommand();
System.out.println(Thread.currentThread().getName() + " 结束执行命令");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.command;
}
}
}