多线程(三) 1. 线程池1.1 线程状态介绍当线程被创建并启动以后它既不是一启动就进入了执行状态也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢Java中的线程状态被定义在了java.lang.Thread.State枚举类中State枚举类的源码如下public class Thread { public enum State { /* 新建 */ NEW , /* 可运行状态 */ RUNNABLE , /* 阻塞状态 */ BLOCKED , /* 无限等待状态 */ WAITING , /* 计时等待 */ TIMED_WAITING , /* 终止 */ TERMINATED; } // 获取当前线程的状态 public State getState() { return jdk.internal.misc.VM.toThreadState(threadStatus); } }通过源码我们可以看到Java中的线程存在6种状态每种线程状态的含义如下线程状态具体含义NEW一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建但是并未启动。还没调用start方法。MyThread t new MyThread()只有线程象没有线程特征。RUNNABLE当我们调用线程对象的start方法那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程线程一经启动并不是立即得到执行线程的运行与否要听令与CPU的调度那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格但是并没有真正的执行起来而是在等待CPU的度。BLOCKED当一个线程试图获取一个对象锁而该对象锁被其他的线程持有则该线程进入Blocked状态当该线程持有锁时该线程将变成Runnable状态。WAITING一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种分别是调用Object.wait()、join()方法。处于等待状态的线程正在等待其他线程去执行一个特定的操作。例如因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll()一个因为join()而等待的线程正在等待另一个线程结束。TIMED_WAITING一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种分别是Thread.sleep(long)Object.wait(long)、join(long)。TERMINATED一个完全运行完成的线程的状态。也称之为终止状态、结束状态各个状态的转换如下图所示1.2 线程池-基本原理概述 :提到池大家应该能想到的就是水池。水池就是一个容器在该容器中存储了很多的水。那么什么是线程池呢线程池也是可以看做成一个池子在该池子中存储很多个线程。线程池存在的意义系统创建一个线程的成本是比较高的因为它涉及到与操作系统交互当程序中需要创建大量生存期很短暂的线程时频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理是对系统资源的消耗这样就有点舍本逐末了。针对这一种情况为了提高性能我们就可以采用线程池。线程池在启动的时会创建大量空闲线程当我们向线程池提交任务的时线程池就会启动一个线程来执行该任务。等待任务执行完毕以后线程并不会死亡而是再次返回到线程池中称为空闲状态。等待下一次任务的执行。线程池的设计思路 :准备一个任务容器一次性启动多个(2个)消费者线程刚开始任务容器是空的所以线程都在wait直到一个外部线程向这个任务容器中扔了一个任务就会有一个消费者线程被唤醒这个消费者线程取出任务并且执行这个任务执行完毕后继续等待下一次任务的到来1.3 线程池-Executors默认线程池概述 : JDK对线程池也进行了相关的实现在真实企业开发中我们也很少去自定义线程池而是使用JDK中自带的线程池。我们可以使用Executors中所提供的静态方法来创建线程池static ExecutorService newCachedThreadPool() 创建一个默认的线程池 static newFixedThreadPool(int nThreads) 创建一个指定最多线程数量的线程池代码实现 :package com.itheima.mythreadpool; //static ExecutorService newCachedThreadPool() 创建一个默认的线程池 //static newFixedThreadPool(int nThreads) 创建一个指定最多线程数量的线程池 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyThreadPoolDemo { public static void main(String[] args) throws InterruptedException { //1,创建一个默认的线程池对象.池子中默认是空的.默认最多可以容纳int类型的最大值. ExecutorService executorService Executors.newCachedThreadPool(); //Executors --- 可以帮助我们创建线程池对象 //ExecutorService --- 可以帮助我们控制线程池 executorService.submit(()-{ System.out.println(Thread.currentThread().getName() 在执行了); }); //Thread.sleep(2000); executorService.submit(()-{ System.out.println(Thread.currentThread().getName() 在执行了); }); executorService.shutdown(); } }1.4 线程池-Executors创建指定上限的线程池使用Executors中所提供的静态方法来创建线程池static ExecutorService newFixedThreadPool(int nThreads) : 创建一个指定最多线程数量的线程池代码实现 :package com.itheima.mythreadpool; //static ExecutorService newFixedThreadPool(int nThreads) //创建一个指定最多线程数量的线程池 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class MyThreadPoolDemo2 { public static void main(String[] args) { //参数不是初始值而是最大值 ExecutorService executorService Executors.newFixedThreadPool(10); ThreadPoolExecutor pool (ThreadPoolExecutor) executorService; System.out.println(pool.getPoolSize());//0 executorService.submit(()-{ System.out.println(Thread.currentThread().getName() 在执行了); }); executorService.submit(()-{ System.out.println(Thread.currentThread().getName() 在执行了); }); System.out.println(pool.getPoolSize());//2 // executorService.shutdown(); } }1.5 线程池-ThreadPoolExecutor创建线程池对象 :ThreadPoolExecutor threadPoolExecutor new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);代码实现 :package com.itheima.mythreadpool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class MyThreadPoolDemo3 { // 参数一核心线程数量 // 参数二最大线程数 // 参数三空闲线程最大存活时间 // 参数四时间单位 // 参数五任务队列 // 参数六创建线程工厂 // 参数七任务的拒绝策略 public static void main(String[] args) { ThreadPoolExecutor pool new ThreadPoolExecutor(2,5,2,TimeUnit.SECONDS,new ArrayBlockingQueue(10), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); pool.shutdown(); } }1.6 线程池-参数详解public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueRunnable workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) corePoolSize 核心线程的最大值不能小于0 maximumPoolSize最大线程数不能小于等于0maximumPoolSize corePoolSize keepAliveTime 空闲线程最大存活时间,不能小于0 unit 时间单位 workQueue 任务队列不能为null threadFactory 创建线程工厂,不能为null handler 任务的拒绝策略,不能为null1.7 线程池-非默认任务拒绝策略RejectedExecutionHandler是jdk提供的一个任务拒绝策略接口它下面存在4个子类。ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。是默认的策略。 ThreadPoolExecutor.DiscardPolicy 丢弃任务但是不抛出异常 这是不推荐的做法。 ThreadPoolExecutor.DiscardOldestPolicy 抛弃队列中等待最久的任务 然后把当前任务加入队列中。 ThreadPoolExecutor.CallerRunsPolicy: 调用任务的run()方法绕过线程池直接执行。注明确线程池对多可执行的任务数 队列容量 最大线程数案例演示1演示ThreadPoolExecutor.AbortPolicy任务处理策略public class ThreadPoolExecutorDemo01 { public static void main(String[] args) { /** * 核心线程数量为1 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */ ThreadPoolExecutor threadPoolExecutor new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.AbortPolicy()) ; // 提交5个任务而该线程池最多可以处理4个任务当我们使用AbortPolicy这个任务处理策略的时候就会抛出异常 for(int x 0 ; x 5 ; x) { threadPoolExecutor.submit(() - { System.out.println(Thread.currentThread().getName() ---- 执行了任务); }); } } }控制台输出结果pool-1-thread-1---- 执行了任务 pool-1-thread-3---- 执行了任务 pool-1-thread-2---- 执行了任务 pool-1-thread-3---- 执行了任务控制台报错仅仅执行了4个任务有一个任务被丢弃了案例演示2演示ThreadPoolExecutor.DiscardPolicy任务处理策略public class ThreadPoolExecutorDemo02 { public static void main(String[] args) { /** * 核心线程数量为1 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */ ThreadPoolExecutor threadPoolExecutor new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardPolicy()) ; // 提交5个任务而该线程池最多可以处理4个任务当我们使用DiscardPolicy这个任务处理策略的时候控制台不会报错 for(int x 0 ; x 5 ; x) { threadPoolExecutor.submit(() - { System.out.println(Thread.currentThread().getName() ---- 执行了任务); }); } } }控制台输出结果pool-1-thread-1---- 执行了任务 pool-1-thread-1---- 执行了任务 pool-1-thread-3---- 执行了任务 pool-1-thread-2---- 执行了任务控制台没有报错仅仅执行了4个任务有一个任务被丢弃了案例演示3演示ThreadPoolExecutor.DiscardOldestPolicy任务处理策略public class ThreadPoolExecutorDemo02 { public static void main(String[] args) { /** * 核心线程数量为1 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */ ThreadPoolExecutor threadPoolExecutor; threadPoolExecutor new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardOldestPolicy()); // 提交5个任务 for(int x 0 ; x 5 ; x) { // 定义一个变量来指定指定当前执行的任务;这个变量需要被final修饰 final int y x ; threadPoolExecutor.submit(() - { System.out.println(Thread.currentThread().getName() ---- 执行了任务 y); }); } } }控制台输出结果pool-1-thread-2---- 执行了任务2 pool-1-thread-1---- 执行了任务0 pool-1-thread-3---- 执行了任务3 pool-1-thread-1---- 执行了任务4由于任务1在线程池中等待时间最长因此任务1被丢弃。案例演示4演示ThreadPoolExecutor.CallerRunsPolicy任务处理策略public class ThreadPoolExecutorDemo04 { public static void main(String[] args) { /** * 核心线程数量为1 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */ ThreadPoolExecutor threadPoolExecutor; threadPoolExecutor new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS , new ArrayBlockingQueue(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.CallerRunsPolicy()); // 提交5个任务 for(int x 0 ; x 5 ; x) { threadPoolExecutor.submit(() - { System.out.println(Thread.currentThread().getName() ---- 执行了任务); }); } } }控制台输出结果pool-1-thread-1---- 执行了任务 pool-1-thread-3---- 执行了任务 pool-1-thread-2---- 执行了任务 pool-1-thread-1---- 执行了任务 main---- 执行了任务通过控制台的输出我们可以看到次策略没有通过线程池中的线程执行任务而是直接调用任务的run()方法绕过线程池直接执行。2. 多线程综合练习练习一售票需求一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,请用多线程模拟卖票过程并打印剩余电影票的数量代码示例public class MyThread extends Thread { //第一种方式实现多线程测试类中MyThread会创建多次所以需要加static static int ticket 1000; Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据已经到末尾 if (ticket 0) { break; } else { //4.判断共享数据没有到末尾 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } ticket--; System.out.println(getName() 在卖票还剩下 ticket 张票!!!); } } } } } public class Test { public static void main(String[] args) { /* 一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒, 要求:请用多线程模拟卖票过程并打印剩余电影票的数量 */ //创建线程对象 MyThread t1 new MyThread(); MyThread t2 new MyThread(); //给线程设置名字 t1.setName(窗口1); t2.setName(窗口2); //开启线程 t1.start(); t2.start(); } }练习二赠送礼物需求有100份礼品,两人同时发送当剩下的礼品小于10份的时候则不再送出。利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来.public class MyRunable implements Runnable { //第二种方式实现多线程测试类中MyRunable只创建一次所以不需要加static int count 100; Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据已经到末尾 if (count 10) { System.out.println(礼物还剩下 count 不再赠送); break; } else { //4.判断共享数据没有到末尾 count--; System.out.println(Thread.currentThread().getName() 在赠送礼物还剩下 count 个礼物!!!); } } } } } public class Test { public static void main(String[] args) { /* 有100份礼品,两人同时发送当剩下的礼品小于10份的时候则不再送出 利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来. */ //创建参数对象 MyRunable mr new MyRunable(); //创建线程对象 Thread t1 new Thread(mr,窗口1); Thread t2 new Thread(mr,窗口2); //启动线程 t1.start(); t2.start(); } }练习三打印数字需求同时开启两个线程共同获取1-100之间的所有数字。将输出所有的奇数。public class MyRunable implements Runnable { //第二种方式实现多线程测试类中MyRunable只创建一次所以不需要加static int number 1; Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据已经到末尾 if (number 100) { break; } else { //4.判断共享数据没有到末尾 if(number % 2 1){ System.out.println(Thread.currentThread().getName() 打印数字 number); } number; } } } } } public class Test { public static void main(String[] args) { /* 同时开启两个线程共同获取1-100之间的所有数字。 要求将输出所有的奇数。 */ //创建参数对象 MyRunable mr new MyRunable(); //创建线程对象 Thread t1 new Thread(mr,线程A); Thread t2 new Thread(mr,线程B); //启动线程 t1.start(); t2.start(); } }练习四抢红包需求抢红包也用到了多线程。假设100块分成了3个包现在有5个人去抢。其中红包是共享数据。5个人是5条线程。打印结果如下XXX抢到了XXX元XXX抢到了XXX元XXX抢到了XXX元XXX抢到了XXX元XXX没抢到public class MyThread extends Thread{ //共享数据 //100块分成了3个包 static double money 100; static int count 3; //最小的中奖金额 static final double MIN 0.01; Override public void run() { //同步代码块 synchronized (MyThread.class){ if(count 0){ //判断共享数据是否到了末尾已经到末尾 System.out.println(getName() 没有抢到红包); }else{ //判断共享数据是否到了末尾没有到末尾 //定义一个变量表示中奖的金额 double prize 0; if(count 1){ //表示此时是最后一个红包 //就无需随机剩余所有的钱都是中奖金额 prize money; }else{ //表示第一次第二次随机 Random r new Random(); //100 元 3个包 //第一个红包99.98 //100 - (3-1) * 0.01 double bounds money - (count - 1) * MIN; prize r.nextDouble(bounds); if(prize MIN){ prize MIN; } } //从money当中去掉当前中奖的金额 money money - prize; //红包的个数-1 count--; //本次红包的信息进行打印 System.out.println(getName() 抢到了 prize 元); } } } } public class Test { public static void main(String[] args) { /* 微信中的抢红包也用到了多线程。 假设100块分成了3个包现在有5个人去抢。 其中红包是共享数据。 5个人是5条线程。 打印结果如下 XXX抢到了XXX元 XXX抢到了XXX元 XXX抢到了XXX元 XXX没抢到 XXX没抢到 */ //创建线程的对象 MyThread t1 new MyThread(); MyThread t2 new MyThread(); MyThread t3 new MyThread(); MyThread t4 new MyThread(); MyThread t5 new MyThread(); //给线程设置名字 t1.setName(小A); t2.setName(小QQ); t3.setName(小哈哈); t4.setName(小诗诗); t5.setName(小丹丹); //启动线程 t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }练习五抽奖箱需求有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”“抽奖箱2”随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:每次抽出一个奖项就打印一个(随机)抽奖箱1 又产生了一个 10 元大奖抽奖箱1 又产生了一个 100 元大奖抽奖箱1 又产生了一个 200 元大奖抽奖箱1 又产生了一个 800 元大奖抽奖箱2 又产生了一个 700 元大奖public class MyThread extends Thread { ArrayListInteger list; public MyThread(ArrayListInteger list) { this.list list; } Override public void run() { //1.循环 //2.同步代码块 //3.判断 //4.判断 while (true) { synchronized (MyThread.class) { if (list.size() 0) { break; } else { //继续抽奖 Collections.shuffle(list); int prize list.remove(0); System.out.println(getName() 又产生了一个 prize 元大奖); } } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Test { public static void main(String[] args) { /* 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700}; 创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”“抽奖箱2” 随机从抽奖池中获取奖项元素并打印在控制台上,格式如下: 每次抽出一个奖项就打印一个(随机) 抽奖箱1 又产生了一个 10 元大奖 抽奖箱1 又产生了一个 100 元大奖 抽奖箱1 又产生了一个 200 元大奖 抽奖箱1 又产生了一个 800 元大奖 抽奖箱2 又产生了一个 700 元大奖 ..... */ //创建奖池 ArrayListInteger list new ArrayList(); Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700); //创建线程 MyThread t1 new MyThread(list); MyThread t2 new MyThread(list); //设置名字 t1.setName(抽奖箱1); t2.setName(抽奖箱2); //启动线程 t1.start(); t2.start(); } }练习六多线程统计并求最大值需求在上一题基础上继续完成如下需求每次抽的过程中不打印抽完时一次性打印(随机)在此次抽奖过程中抽奖箱1总共产生了6个奖项。分别为10,20,100,500,2,300最高奖项为300元总计额为932元在此次抽奖过程中抽奖箱2总共产生了6个奖项。分别为5,50,200,800,80,700最高奖项为800元总计额为1835元解决方案一public class MyThread extends Thread { ArrayListInteger list; public MyThread(ArrayListInteger list) { this.list list; } //线程一 static ArrayListInteger list1 new ArrayList(); //线程二 static ArrayListInteger list2 new ArrayList(); Override public void run() { while (true) { synchronized (MyThread.class) { if (list.size() 0) { if(抽奖箱1.equals(getName())){ System.out.println(抽奖箱1 list1); }else { System.out.println(抽奖箱2 list2); } break; } else { //继续抽奖 Collections.shuffle(list); int prize list.remove(0); if(抽奖箱1.equals(getName())){ list1.add(prize); }else { list2.add(prize); } } } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Test { public static void main(String[] args) { /* 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700}; 创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”“抽奖箱2” 随机从抽奖池中获取奖项元素并打印在控制台上,格式如下: 每次抽的过程中不打印抽完时一次性打印(随机) 在此次抽奖过程中抽奖箱1总共产生了6个奖项。 分别为10,20,100,500,2,300最高奖项为300元总计额为932元 在此次抽奖过程中抽奖箱2总共产生了6个奖项。 分别为5,50,200,800,80,700最高奖项为800元总计额为1835元 */ //创建奖池 ArrayListInteger list new ArrayList(); Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700); //创建线程 MyThread t1 new MyThread(list); MyThread t2 new MyThread(list); //设置名字 t1.setName(抽奖箱1); t2.setName(抽奖箱2); //启动线程 t1.start(); t2.start(); } }解决方案二public class MyThread extends Thread { ArrayListInteger list; public MyThread(ArrayListInteger list) { this.list list; } Override public void run() { ArrayListInteger boxList new ArrayList();//1 //2 while (true) { synchronized (MyThread.class) { if (list.size() 0) { System.out.println(getName() boxList); break; } else { //继续抽奖 Collections.shuffle(list); int prize list.remove(0); boxList.add(prize); } } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Test { public static void main(String[] args) { /* 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700}; 创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”“抽奖箱2” 随机从抽奖池中获取奖项元素并打印在控制台上,格式如下: 每次抽的过程中不打印抽完时一次性打印(随机) 在此次抽奖过程中抽奖箱1总共产生了6个奖项。 分别为10,20,100,500,2,300最高奖项为300元总计额为932元 在此次抽奖过程中抽奖箱2总共产生了6个奖项。 分别为5,50,200,800,80,700最高奖项为800元总计额为1835元 */ //创建奖池 ArrayListInteger list new ArrayList(); Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700); //创建线程 MyThread t1 new MyThread(list); MyThread t2 new MyThread(list); //设置名字 t1.setName(抽奖箱1); t2.setName(抽奖箱2); //启动线程 t1.start(); t2.start(); } }练习七多线程之间的比较需求在上一题基础上继续完成如下需求在此次抽奖过程中抽奖箱1总共产生了6个奖项分别为10,20,100,500,2,300最高奖项为300元总计额为932元在此次抽奖过程中抽奖箱2总共产生了6个奖项分别为5,50,200,800,80,700最高奖项为800元总计额为1835元在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元以上打印效果只是数据模拟,实际代码运行的效果会有差异public class MyCallable implements CallableInteger { ArrayListInteger list; public MyCallable(ArrayListInteger list) { this.list list; } Override public Integer call() throws Exception { ArrayListInteger boxList new ArrayList();//1 //2 while (true) { synchronized (MyCallable.class) { if (list.size() 0) { System.out.println(Thread.currentThread().getName() boxList); break; } else { //继续抽奖 Collections.shuffle(list); int prize list.remove(0); boxList.add(prize); } } Thread.sleep(10); } //把集合中的最大值返回 if(boxList.size() 0){ return null; }else{ return Collections.max(boxList); } } } package com.itheima.test7; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { /* 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700}; 创建两个抽奖箱(线程)设置线程名称分别为 抽奖箱1, 抽奖箱2 随机从抽奖池中获取奖项元素并打印在控制台上,格式如下: 在此次抽奖过程中抽奖箱1总共产生了6个奖项分别为10,20,100,500,2,300 最高奖项为300元总计额为932元 在此次抽奖过程中抽奖箱2总共产生了6个奖项分别为5,50,200,800,80,700 最高奖项为800元总计额为1835元 在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元 核心逻辑获取线程抽奖的最大值看成是线程运行的结果 以上打印效果只是数据模拟,实际代码运行的效果会有差异 */ //创建奖池 ArrayListInteger list new ArrayList(); Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700); //创建多线程要运行的参数对象 MyCallable mc new MyCallable(list); //创建多线程运行结果的管理者对象 //线程一 FutureTaskInteger ft1 new FutureTask(mc); //线程二 FutureTaskInteger ft2 new FutureTask(mc); //创建线程对象 Thread t1 new Thread(ft1); Thread t2 new Thread(ft2); //设置名字 t1.setName(抽奖箱1); t2.setName(抽奖箱2); //开启线程 t1.start(); t2.start(); Integer max1 ft1.get(); Integer max2 ft2.get(); System.out.println(max1); System.out.println(max2); //在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元 if(max1 null){ System.out.println(在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为max2元); }else if(max2 null){ System.out.println(在此次抽奖过程中,抽奖箱1中产生了最大奖项,该奖项金额为max1元); }else if(max1 max2){ System.out.println(在此次抽奖过程中,抽奖箱1中产生了最大奖项,该奖项金额为max1元); }else if(max1 max2){ System.out.println(在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为max2元); }else{ System.out.println(两者的最大奖项是一样的); } } }