Java线程(线程池、创建线程的第三种方法callable)
线程池
补充资料:Doug Lea (JCP组织的一人)对线程池部分贡献巨大
常用线程池的接口和类:
Executor:线程池的顶级接口
ExecutorService:线程池接口可用submit(Runnable Task)提交任务代码。包含:Shutdown;
Shutdownnow等
Executors工厂类:可以通过这一个方法得到一个线程池
NewFixedThreadPool(int n Thread):获取固定数量的线程池。参数:指线程池中线程的数量
NewCacheThreadPool()获取动态数量的线程池,无上限
对于ExecutorService:需关注实现类TheadPoolExecutor,SheduledThreadPoolExecutor
Executors:1.创建固定线程个数的线程池
2.创建缓存线程池,又任务多少来决定
3.创建单线程池
4.创建调度线程池 调度:周期、定时执行
在API中:
Shutdown:启动一次顺序关闭,执行以前提交的任务,但不接受新任务
ShutDownNow:试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表
代码示例1 固定线程个数:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo { public static void main(String[] args) { // 1.创建固定线程个数的线程池 ExecutorService es=Executors.newFixedThreadPool(4); // 2.提交任务 Runnable run=new Runnable() { private int ticket; @Override public void run() { while (true) { if (ticket <= 0) { break; } System.out.println(Thread.currentThread().getName() + "卖完第:" + ticket + "张票"); ticket--; } } }; // 3.提交任务 for(int i=0;i<=4;i++) { es.submit(run); } // 4.关闭线程池 es.shutdown(); } }
代码示例 2 可变线程个数,由任务决定
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo { public static void main(String[] args) { // 1.创建固定线程个数的线程池 // ExecutorService es=Executors.newFixedThreadPool(4); ExecutorService es2=Executors.newCachedThreadPool(); // 2.提交任务 Runnable run=new Runnable() { private int ticket; @Override public void run() { while (true) { if (ticket <= 0) { break; } System.out.println(Thread.currentThread().getName() + "卖完第:" + ticket + "张票"); ticket--; } } }; // 3.提交任务 for(int i=0;i<=4;i++) { es2.submit(run); } // 4.关闭线程池 es2.shutdown(); } }
注:提交任务数不一定是4.要具体看运行结果
Excutors的另外两种方法
3. ExecutorService e3=Executors.newSingleThreadExecutor();
4. ExecutorService e4=Executors.newScheduledThreadPool();
Callable接口
语法:
Public interface Callable<V>{public V call() throws Exception}
特点:有返回值;使用时需要先转化为任务后被Thread调用
代码示例:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; public class Demo02 { public static void main(String[] args) { // 功能需求:计算1-100的和并使用Callable接口 Callable<Integer> callable=new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"开始计算"); int sum = 0; for (int j = 1;j<=100;j++){ sum+=j; Thread.sleep(100); } return sum; } }; // 把Callable转化为可执行的任务 FutureTask<Integer> task = new FutureTask<>(callable); // 创建线程 Thread thread = new Thread(task); // 启动线程 thread.start(); // 获取结果 Integer sum= null; try { sum = task.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("结果是"+sum); } }
Callable与线程池的结合的使用
这种方法与线程池的配合更为紧密
优点:无需先转化为task,再进行执行;
需求示例:使用Callable和线程池计算1-100的和
代码示例:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo03 { public static void main(String[] args) throws Exception { // 1. 创建线程池 ExecutorService es = Executors.newFixedThreadPool(1); // 2.提交任务Future:表示将要执行任务的结果 Future<Integer> future = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"开始计算"); int sum=0; for (int i=0;i<=100;i++){ sum+=i; } return sum; } }); // 3.获取任务结果 System.out.println(future.get()); // 4.关闭线程池 es.shutdown(); } }
Future接口
功能:表示将要完成的任务的结果
案例需求:使用两个线程,并发计算1-50和51-100的和,再进行汇总统计
Future.get()方法需要等待callable的方法执行完毕才可以继续执行,即 同步
关于同步、异步:我们现在手头有两个线程A\B,A在使用过程中会调用B线程。同步的含义是例如A需要执行三个部分,在第一个部分时调用了B,调用之后不继续执行第二个部分而是等待B被调用完之后再继续执行第二第三个部分。
异步的含义是,A执行第一部分并调用了B线程,A不继续等待B线程执行完而接着执行第二部分第三部分。
代码示例:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo4 { public static void main(String[] args) throws Exception{ // 1.创建线程池 ExecutorService es = Executors.newFixedThreadPool(2); // 2.创建任务及对象 Future<Integer> future =es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int sum=0; for(int i=0;i<=50;i++){ sum+=i; } return sum; } }); Future<Integer> future2=es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int sum=0; for(int i=51;i<=100;i++){ sum+=i; } return sum; } }); // 3.获取结果 int sum=future.get()+future2.get(); System.out.println("结果是" + sum); // 4.关闭线程 es.shutdown(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!