在进行多线程编程时,通常可以采用以下四种方式来实现:
1. 继承Thread类,重写run()方法
这种方式需要继承Thread类并重写run()方法,然后通过创建子类对象来启动线程。例如:
```
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行代码
}
}
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
```
2. 实现Runnable接口
这种方式需要创建一个实现了Runnable接口的类,并重写run()方法。然后将该实现类的实例作为参数传递给Thread类的构造方法,并调用start()方法启动线程。例如:
```
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行代码
}
}
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
}
```
3. 实现Callable接口
Callable接口类似于Runnable接口,都是用来创建线程的,但它比Runnable接口强大,可以返回执行结果,并且可以抛出异常。需要创建一个实现了Callable接口的类,并重写call()方法。然后可以通过创建ExecutorService对象来启动线程。例如:
```
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// 线程执行代码
return "result";
}
}
public static void main(String[] args) {
MyCallable c = new MyCallable();
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(c);
String result = future.get();
}
```
4. 使用线程池
在创建大量线程时,如果每个线程都创建一个新的线程对象,将消耗大量的系统资源,此时可以使用线程池来管理线程。线程池是一种线程复用的方法,它可以预先创建一定数量的线程,并将任务提交给线程池,由线程池中的空闲线程来执行任务。例如:
```
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
// 线程执行代码
}
});
}
executorService.shutdown();
}
```
这四种方式的区别主要在于实现方式的不同,功能上基本相同,都可以用来创建和启动线程,但底层实现不同。比如,使用Runnable接口的方式可以让多个线程共享同一个Runnable对象,而使用Callable接口可以返回执行结果和抛出异常等。使用线程池可以提高线程的复用性,减小系统开销等。