目录
- 方法一:继承Thread类
- 方法二:实现Runnable接口
- 方法三:实现Callable接口
- 方法四:ThreadPoolExecutor执行Runnable任务
- 方法五:ThreadPoolExecutor执行Callable任务
- 方法六:Executors工具类实现线程池
方法一:继承Thread类
定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
创建MyThread类的对象
调用线程对象的start()方法启动线程(启动后还是执行run方法的)
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于扩展。不适合需要返回线程执行结果的业务场景。
/**方式一:继承Thread类实现*/
public class ThreadDemo1 {public static void main(String[] args) {// 3、new一个新线程对象Thread t = new MyThread();// 4、调用start方法启动线程(执行的还是run方法)t.start();for (int i = 0; i < 5; i++) {System.out.println("主线程执行输出:" + i);}}
}/**1、定义一个线程类继承Thread类*/
class MyThread extends Thread{/**2、重写run方法,里面是定义线程以后要干啥*/@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程执行输出:" + i);}}
}
方法二:实现Runnable接口
定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
创建MyRunnable任务对象
把MyRunnable任务对象交给Thread处理。
调用线程对象的start()方法启动线程
构造器 | 说明 |
---|---|
public Thread(String name) | 可以为当前线程指定名称 |
public Thread(Runnable target) | 封装Runnable对象成为线程对象 |
public Thread(Runnable target ,String name ) | 封装Runnable对象成为线程对象,并指定线程名称 |
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
缺点:多一层对象包装,如果线程有执行结果是不可以直接返回的。不适合需要返回线程执行结果的业务场景。
/**方式二:实现Runnable接口*/
public class ThreadDemo2 {public static void main(String[] args) {// 3、创建一个任务对象Runnable target = new MyRunnable();// 4、把任务对象交给Thread处理Thread t = new Thread(target);// Thread t = new Thread(target, "1号");// 5、启动线程t.start();for (int i = 0; i < 10; i++) {System.out.println("主线程执行输出:" + i);}}
}/**1、定义一个线程任务类 实现Runnable接口*/
class MyRunnable implements Runnable {/**2、重写run方法,定义线程的执行任务的*/@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("子线程执行输出:" + i);}}
}
方法三:实现Callable接口
- 得到任务对象
a.定义类实现Callable接口,重写call方法,封装要做的事情。
b.用FutureTask把Callable对象封装成线程任务对象。 - 把线程任务对象交给Thread处理。
- 调用Thread的start方法启动线程,执行任务
- 线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。
方法名称 | 说明 |
---|---|
public FutureTask<>(Callable call) | 把Callable对象封装成FutureTask对象。 |
public V get() throws Exception | 获取线程执行call方法返回的结果。 |
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。可以在线程执行完毕后去获取线程执行的结果。
缺点:编码复杂一点。
/**方式三:实现Callable接口,结合FutureTask完成。*/
public class ThreadDemo3 {public static void main(String[] args) {// 3、创建Callable任务对象Callable<String> call = new MyCallable(100);// 4、把Callable任务对象 交给 FutureTask 对象// FutureTask对象的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread了// FutureTask对象的作用2: 可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果FutureTask<String> f1 = new FutureTask<>(call);// 5、交给线程处理Thread t1 = new Thread(f1);// 6、启动线程t1.start();Callable<String> call2 = new MyCallable(200);FutureTask<String> f2 = new FutureTask<>(call2);Thread t2 = new Thread(f2);t2.start();try {// 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。String rs1 = f1.get();System.out.println("第一个结果:" + rs1);} catch (Exception e) {e.printStackTrace();}try {// 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。String rs2 = f2.get();System.out.println("第二个结果:" + rs2);} catch (Exception e) {e.printStackTrace();}}
}/**1、定义一个任务类 实现Callable接口 应该申明线程任务执行完毕后的结果的数据类型*/
class MyCallable implements Callable<String>{private int n;public MyCallable(int n) {this.n = n;}/**2、重写call方法(任务方法)*/@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n ; i++) {sum += i;}return "子线程执行的结果是:" + sum;}
}
方法四:ThreadPoolExecutor执行Runnable任务
方法名称 | 说明 |
---|---|
void execute(Runnable command) | 执行任务/命令,没有返回值,一般用来执行 Runnable 任务 |
Future submit(Callable task) | 执行Callable任务,返回未来任务对象获取线程结果 |
void shutdown() | 等任务执行完毕后关闭线程池 |
List shutdownNow() | 立刻关闭,停止正在执行的任务,并返回队列中未执行的任务 |
/**方法四:ThreadPoolExecutor执行Runnable任务*/
public class ThreadPoolDemo1 {public static void main(String[] args) {// 1、创建线程池对象/**public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)*/ExecutorService pool = new ThreadPoolExecutor(3, 5 ,6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() );// 2、给任务线程池处理。Runnable target = new MyRunnable();pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);// 创建临时线程pool.execute(target);pool.execute(target);
// // 不创建,拒绝策略被触发!!!
// pool.execute(target);// 关闭线程池(开发中一般不会使用)。// pool.shutdownNow(); // 立即关闭,即使任务没有完成,会丢失任务!pool.shutdown(); // 会等待全部任务执行完毕之后再关闭(建议使用)}
}
方法五:ThreadPoolExecutor执行Callable任务
/**目标:自定义一个线程池对象,并测试其特性。*/
public class ThreadPoolDemo2 {public static void main(String[] args) throws Exception {// 1、创建线程池对象/**public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)*/ExecutorService pool = new ThreadPoolExecutor(3, 5 ,6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() );// 2、给任务线程池处理。Future<String> f1 = pool.submit(new MyCallable(100));Future<String> f2 = pool.submit(new MyCallable(200));Future<String> f3 = pool.submit(new MyCallable(300));Future<String> f4 = pool.submit(new MyCallable(400));Future<String> f5 = pool.submit(new MyCallable(500));// String rs = f1.get();
// System.out.println(rs);System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());System.out.println(f5.get());}
}
方法六:Executors工具类实现线程池
方法名称 | 说明 |
---|---|
public static ExecutorService newCachedThreadPool() | 线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉。 |
public static ExecutorService newFixedThreadPool(int nThreads) | 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。 |
public static ExecutorService newSingleThreadExecutor () | 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。 |
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) | 创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。 |
注意:Executors的底层其实也是基于线程池的实现类ThreadPoolExecutor创建线程池对象的。
/**方法六:Executors工具类实现线程池*/
public class ThreadPoolDemo3 {public static void main(String[] args) throws Exception {// 1、创建固定线程数据的线程池ExecutorService pool = Executors.newFixedThreadPool(3);pool.execute(new MyRunnable());pool.execute(new MyRunnable());pool.execute(new MyRunnable());pool.execute(new MyRunnable()); // 没有多余线程}
}