美文网首页
5-10 错误停止线程的方法

5-10 错误停止线程的方法

作者: 西西_20f6 | 来源:发表于2020-07-11 21:14 被阅读0次

    一、使用被弃用的stop,suspend和resume方法

    package threadcoreknpwledge.stopthread;
    
    /**
     * 错误的停止方法:使用stop()来停止线程,会导致线程运行到一半突然停止,
     * 没有办法完成一个基本单位的操作(一个连队)。
     * 会造成脏数据(有的连队会多领取或少领取装备)。
     *  导致对象被破坏,数据不一致的情况
     */
    public class StopThread implements Runnable{
        
        public static void main(String[] args) {
        
            Thread thread = new Thread(new StopThread());
            thread.start();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread.stop();
        }
        
        /**
         * 模拟指挥军队:一共5个连队,每个连队10人
         * 以连队为单位发放武器弹药,叫到号的士兵前去领取
         */
        @Override
        public void run() {
            for(int i=0;i<5;i++){
                System.out.println("连队"+i+"开始领取武器");
                for(int j=0;j<10;j++){
                    System.out.println(j);
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("连队"+i+"完成武器领取工作");
            }
        }
    }
    
    

    2,suspend
    suspend会让一个线程挂起,在该线程恢复之前,是不会释放锁的,它是带着锁进行休息的,容易造成死锁,如果没有其他线程来恢复它,它就会一直不释放锁等待下去。。。

    二、 用volatile设置boolean标记位
    1,看似可行

    package threadcoreknpwledge.stopthread.volatiledemo;
    
    /**
     * 演示volatile的局限:part1 boolean flag似可行
     *
     */
    public class WrongWayVolatile implements Runnable {
        
        private volatile boolean canceled = false;
        
        
        @Override
        public void run() {
            int num = 0;
            try {
                while (num <= 10000 && !canceled) {
                    if (num % 100 == 0) {
                        System.out.println(num + "是100的倍数");
                    }
                    num++;
                    Thread.sleep(1);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("结束任务");
        }
        
        public static void main(String[] args) throws InterruptedException {
            WrongWayVolatile runnable = new WrongWayVolatile();
            Thread thread = new Thread(runnable);
            thread.start();
            Thread.sleep(5000);
            runnable.canceled = true;
            
        }
    }
    
    

    2,当陷入阻塞,volatile是无法停止线程的

    package threadcoreknpwledge.stopthread.volatiledemo;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    
    
    /**
     * 演示volatile局限:part2
     * 当陷入阻塞,volatile是无法停止线程的,此例中
     * 生产者的生产速度很快,消费者的消费速度很慢
     * 就会出现阻塞队列满了的情况,生产者就阻塞了
     *
     * 为什么这些阻塞方法都加上了throw InterruptedException,
     * 是想让它们在阻塞的时候也能够响应(通过抛异常的方式响应)接收到的中断信号。
     */
    public class WrongWayVolatileCantStop {
        
        public static void main(String[] args) throws InterruptedException {
            ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
            
            Producer producer = new Producer(storage);
            Thread producerThread = new Thread(producer);
            producerThread.start();
            Thread.sleep(1000);
            Consumer consumer = new Consumer(storage);
            while (consumer.needMoreNums()) {
                //consumer still need number
                System.out.println(consumer.storage.take() + "被消费了");
                Thread.sleep(100);
            }
            //consumer no need number any more
            System.out.println("消费不需要更多数据了");
            //一旦消费者不需要更多数据,就应该让生产者不再生产数据。
            //但是实际情况,如果Producer被阻塞了,是无法响应这个producer.canceled
            producer.canceled = true;
            System.out.println("producer.canceled = " + producer.canceled);
        }
        
        
    }
    
    class Producer implements Runnable {
        BlockingQueue storage;
        public volatile boolean canceled = false;
        
        public Producer(BlockingQueue storage) {
            this.storage = storage;
        }
        
        @Override
        public void run() {
            int num = 0;
            try {
                while (num <= 100000 && !canceled) {
                    if (num % 100 == 0) {
                        System.out.println(num + "是100的倍数,准备放到仓库中。");
                        storage.put(num);//生产者阻塞在这里了
                        System.out.println(num + "是100的倍数,已经放到仓库中。");
                    }
                    num++;
                }
                System.out.println("canceled = "+canceled);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("生产者结束运行");
            }
            
        }
    }
    
    class Consumer {
        BlockingQueue storage;
        public volatile boolean canceled = false;
        
        public Consumer(BlockingQueue storage) {
            this.storage = storage;
        }
        
        public boolean needMoreNums() {
            if (Math.random() > 0.95) {
                return false;
            }
            return true;
        }
    }
    

    java内存结构和Java内存模型

    相关文章

      网友评论

          本文标题:5-10 错误停止线程的方法

          本文链接:https://www.haomeiwen.com/subject/zuphcktx.html