一、线程的创建
(1)继承Thread类
需要实现run方法,通过调用start方法启动线程
public class MyThread extends Thread{
@Override
public void run(){//实现run方法
//以下根据自己的需要来写,这里打印示例1~9
for(int i=1; i<10; i++){
System.out.print(i + " ");
}
}
}
public class TestMyThread {
public static void main(String[] args) {
MyThread m1 = new MyThread();
m1.start();
}
}
(2)实现Runnable接口
同样需要实现run方法,通过Thread调用start()方法来启动线程
与Callable相比,没有返回值
public class MyRunnable implements Runnable{
@Override
public void run() {//同样需要实现run方法
for(int i=0; i<10; i++){
System.out.print(i + " ");
}
}
}
public class TestMyRunnable {
public static void main(String[] args){
MyRunnable mr = new MyRunnable();
//通过Thread调用start()方法来启动线程
Thread thread = new Thread(mr);
thread.start();
}
}
(3)实现Callable接口
与Runnable相比,Callable提供了call()方法作为线程执行体,类似于run方法,但功能更加强大。
Callable可以有返回值,返回值需要通过FutureTask 进行封装。FutureTask 实现了Future接口和Runnable接口,因而也需要通过Thread调用start()方法来启动线程
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {//实现call方法
int i=0;
for(; i<10; i++){
System.out.print(i + " ");
}
return i;//返回值
}
}
public class TestMyCallable {
public static void main(String[] args) throws InterruptedException, ExecutionException{
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);//封装
Thread thread = new Thread(ft);
thread.start();
//返回值通过FutureTask对象的get方法获得
System.out.println("打印返回值:"+ft.get());
}
}
(4)通过线程池(如Executor)创建
Executor 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。Executor框架的内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。
Executor主要有三种:
- CachedThreadPool:一个任务创建一个线程;
- FixedThreadPool:所有任务只能使用固定大小的线程;
- SingleThreadExecutor:相当于大小为 1 的 FixedThreadPool。
public class MyExecutor {
public static void main(String[] args){
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0; i<3; i++){//创建3个MyRunnable进程
es.execute(new MyRunnable());
}
es.shutdown();//关闭ExecutorService
}
}
Executor接口中之定义了一个方法execute(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类。ExecutorService接口继承自Executor接口,它提供了更丰富的实现多线程的方法,比如,ExecutorService提供了关闭自己的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以调用ExecutorService的shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。因此我们一般用该接口来实现和管理多线程。
ExecutorService的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了的任务,当素有已经提交了的任务执行完后,便到达终止状态。如果不调用shutdown()方法,ExecutorService会一直处在运行状态,不断接收新的任务,执行新的任务,服务器端一般不需要关闭它,保持一直运行即可。
二、总结
(1)关于创建进程,最好通过实现接口方式,因为java不支持多继承,继承了 Thread 类就无法继承其它类,但是可以实现多个接口;
(2)通过Executor来启动线程比使用Thread的start方法更好,更易管理,效率更好(用线程池实现,节约开销)
三、参考
https://github.com/CyC2018/CS-Notes/blob/master/notes/Java 并发.md