美文网首页
java并发编程知识梳理

java并发编程知识梳理

作者: 台风口的猪 | 来源:发表于2019-06-19 15:06 被阅读0次
    
    @Slf4j
    public class ThreadDemo {
    
        public static void main(String[] args) throws InterruptedException {
            // 启动10个线程
            ExecutorService threadPool = Executors.newFixedThreadPool(10);
            Counter counter = new Counter();
            // 同时500000个用户过来请求 
            for (int i = 1; i <= 500000; i++) {
               //            threadPool.submit(new Runnable() {
              //                @Override
             //                public void run() {
            //                    counter.increment();
           //                }
          //            }); 
                threadPool.submit(()->counter.increment());
            }
            /**
             * 将线程池状态置为SHUTDOWN,并不会立即停止:
             */
            threadPool.shutdown();
    
         /**
             * 当前线程阻塞,等所有已提交线程执行完 如果执行完则返回true 否则返回false
             */
          threadPool.awaitTermination(60, TimeUnit.SECONDS);
    
            System.out.println("counter  : " + counter.getCount());
        }
    }
    
    
    @Slf4j
    public class Counter {
    
        int count = 0;
    
        public void increment() {
            count = count + 1;
        }
    
        public int getCount() {
            return count;
        }
    }
    

    结果

        counter.getCount()  结果为 499252  499758  499323 每次运行都产生不一样的结果
    

    为什么不一样

        当线程调用increment()方法时,实际上执行了三个步骤
        1. 从内存得到count的值
        2.将count+1
        3.将操作后的值重新存储到内存中
        因为是三个步骤所以并不具备原子性
    

    解决方法

    使用 synchronized

    @Slf4j
    public class Counter {
        int count = 0;
         //  只需要加上synchronized即可
        public synchronized void increment() {
            count = count + 1;
        }
    
        public int getCount() {
            return count;
        }
    }
    

    使用 juc包中的原子类

    @Slf4j
    public class Counter {
    
    
        final AtomicInteger count = new AtomicInteger();
    //    int count = 0;  //使用AtomicInteger代替int
    
        public void increment(){
            count.getAndIncrement();  
            //count++;  //使用 count.getAndIncrement(); 代替count++
        }
    
        public AtomicInteger getCount() {
            return count;
        }
    }
    
    

    使用ReentrantLock

    @Slf4j
    public class Counter {
    
        Lock lock =  new ReentrantLock();
        int count = 0;
    
        public void increment(){
            lock.lock();
            try{
                //业务逻辑处理
                count++;
            }finally {
                lock.unlock(); // 建议在finally处释放锁,以免在运行try{}块时报错,导致最终锁没有释放
            }
        }
    
        public Integer getCount() {
            return count;
        }
    }
    

    ExecutorService 的 shutdown() shutdownNow() awaitTermination() 详解

    shutdown()

    将线程池状态置为SHUTDOWN,并不会立即停止:
     1.停止接收外部submit的任务
     2.内部正在跑的任务和队列里等待的任务,会执行完
     3. 等到2完成后,才真正停止
    

    shutdownNow()

    将线程池状态置为STOP。企图立即停止,但是并不一定:
     1.将shutdown()一样,先停止接收外部提交的任务
     2.忽略队列里等待的任务
     3.尝试将正在跑的任务interrupt中断
     4.返回未执行的任务列表
    

    awaitTermination(long timeOut, TimeUnit unit)

     当前线程阻塞
    等所有已提交的任务执行完(包括正在跑的和队列中等待的)或者等超时时间到或者线程被中断,抛出InterruptedException
    后返回true(shutdown请求后所有任务执行完毕)或false(已超时的任务)
    

    shutdown()和shutdownNow()的区别

     shutdownNow()能立即停止线程池,停止所有的任务(包含正在执行的和正在等待的),风险较大
     shutdown()只是关闭提交通道,等所有的任务跑完后再停止
    

    shutdown()和awaitTermination()的区别

    shutdown()后不能再提交新的任务进去;
    awaitTermination()后可以继续提交。
    awaitTermination()是阻塞的返回结果是线程池是否已停止(true/false);
    shutdown()不阻塞。
    

    总结

    优雅的关闭,用shutdown()
    立马关闭,并得到未执行任务列表,用shutdownNow()
    优雅的关闭,并允许关闭声明后新任务能提交,用awaitTermination()

    相关文章

      网友评论

          本文标题:java并发编程知识梳理

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