如何优雅的停止一个线程?( 三 )

/** * @url: i-code.online * @author: zhoucx * @time: 2020/10/12 10:46 */public class Producter implements Runnable {//标记是否需要产生数字public static volatile boolean mark = true;BlockingQueue numQueue;public Producter(BlockingQueue numQueue){this.numQueue = numQueue;}@Overridepublic void run() {int num = 0;try {while (num < 100000numQueue.put(num);}num++;}} catch (InterruptedException e) {e.printStackTrace();}finally {System.out.println("生产者运行结束....");}}}首先 , 声明了一个生产者 Producer , 通过 volatile标记的初始值为 true 的布尔值 mark 来停止线程 。 而在 run()方法中 , while 的判断语句是 num 是否小于 100000mark 是否被标记 。 while 循环体中判断 num如果是 50 的倍数就放到 numQueue 仓库中 , numQueue 是生产者与消费者之间进行通信的存储器 , 当 num 大于 100000或被通知停止时 , 会跳出 while 循环并执行 finally 语句块 , 告诉大家“生产者运行结束”
/** * @url: i-code.online * @author: zhoucx * @time: 2020/10/12 11:03 */public class Consumer implements Runnable{BlockingQueue numQueue;public Consumer(BlockingQueue numQueue){this.numQueue = numQueue;}@Overridepublic void run() {try {while (Math.random() < 0.97){//进行消费System.out.println(numQueue.take()+"被消费了...");;TimeUnit.MILLISECONDS.sleep(100);}} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println("消费者执行结束...");Producter.mark = false;System.out.println("Producter.mark = "+Producter.mark);}}}而对于消费者 Consumer , 它与生产者共用同一个仓库 numQueue , 在 run() 方法中我们通过判断随机数大小来确定是否要继续消费 , 刚才生产者生产了一些 50 的倍数供消费者使用 , 消费者是否继续使用数字的判断条件是产生一个随机数并与 0.97 进行比较 , 大于 0.97 就不再继续使用数字 。
/** * @url: i-code.online * @author: zhoucx * @time: 2020/10/12 11:08 */public class Mian {public static void main(String[] args) {BlockingQueue queue = new LinkedBlockingQueue(10);Producter producter = new Producter(queue);Consumer consumer = new Consumer(queue);Thread thread = new Thread(producter,"producter-Thread");thread.start();new Thread(consumer,"COnsumer-Thread").start();}}主函数中很简单 , 创建一个 公共仓库 queue 长度为10 , 然后传递给两个线程 , 然后启动两个线程 , 当我们启动后要注意 , 我们的消费时有睡眠 100 毫秒 , 那么这个公共仓库必然会被生产者装满进入阻塞 , 等待消费 。 当消费者不再需要数据 , 就会将 canceled 的标记位设置为 true , 理论上此时生产者会跳出 while 循环 , 并打印输出“生产者运行结束” 。 然而结果却不是我们想象的那样 , 尽管已经把 Producter.mark设置成 false , 但生产者仍然没有停止 , 这是因为在这种情况下 , 生产者在执行 numQueue.put(num) 时发生阻塞 , 在它被叫醒之前是没有办法进入下一次循环判断


推荐阅读