zoukankan      html  css  js  c++  java
  • 并发问题

    最近遇到一个棘手的问题,说棘手一方面之前没考虑过,另一方面其中的业务逻辑实在太难看懂了。

    以后写代码希望以此为戒吧

    1.嵌套层数不要超过3层。

    2.逻辑上超过3层的if-else代码可以使用卫语句,或者状态模式来实现。

    3.对于高并发业务需要考虑多线程并发问题,互斥锁,死锁等问题。

    问题描述:

    1.前端可以触发,根据不同的参数获取不同的处理数据。
    2.后端有自动任务获取数据,并处理数据。(创建线程去处理)

    逻辑主要分3步
    a.获取数据
    b.处理数据(处理时间还有点长)
    c.更新数据

    模拟分析:

    1.多线程,多实例处理

    本人待的项目是很老的项目,以此为背景。service,dao为原型模式,对于数据的模拟采用饥汉式单例模式。

    Data.java

    package com.midea.test;
    
    public class Data {
        
        private static Data data = new Data();
        
        private volatile int num = 10;
        
        private Data(){
            
        }
        
        public static Data getInstance() {
            if (data == null) {
                return new Data();
            }
            return data;
        }
    
        public int getNum() {
            return num;
        }
    
        public void setNum(int num) {
            this.num = num;
        }
    
        
        
    }
    ProductService 
    package com.midea.test;
    
    public class ProductService {
        
        private ProductDao productDao;
    
        public ProductDao getProductDao() {
            return productDao;
        }
    
        public void setProductDao(ProductDao productDao) {
            this.productDao = productDao;
        }
    
        public void process() {
            int n = productDao.getNum();
            System.out.println(Thread.currentThread().getId()+",before:"+n);
            productDao.setNum(n+1);
            System.out.println(Thread.currentThread().getId()+",after:"+productDao.getNum());
            
        }
    
        
        
    }

    ProductDao

    package com.midea.test;
    
    public class ProductDao {
    
        public int getNum() {
            Data data = Data.getInstance();
            return data.getNum();
        }
    
        public void setNum(int num) {
            Data data = Data.getInstance();
            data.setNum(num);
        }
        
    }

    测试

    @Test
        public void test1(){
            
            for (int i=0; i<10; i++) {
                Thread t = new Thread(){
    
                    @Override
                    public void run() {
                        ProductService service = new ProductService();
                        System.out.println(service.hashCode());
                        ProductDao dao = new ProductDao();
                        service.setProductDao(dao);
                        service.process();
                    }
                    
                };
                t.start();
                
            }
            
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
     System.out.println("最后结果:"+Data.getInstance().getNum());
    }

    查看结果:

    service的hashcode不一样,每个service都是一个new的。每个线程都是各自用自己的service去处理的。

    本意是数据 10自增10次,然后得到20,实际结果却不是20

    380254118
    1318663487
    745988969
    827070797
    2064721795
    97255069
    330889316
    13,before:10
    13,after:11
    14,before:10
    14,after:11
    16,before:10
    16,after:11
    10,before:11
    10,after:12
    12,before:10
    12,after:11
    15,before:11
    15,after:12
    11,before:10
    11,after:11
    1421571929
    1603837828
    19,before:11
    19,after:12
    18,before:12
    487638052
    17,before:12
    17,after:13
    18,after:13
    

      

    用于我们业务上是要求

    a.获取数据
    b.处理数据(处理时间还有点长)
    c.更新数据

    获取到数据之后是要用来处理的。这就要求,我获取到的数据是最新的,且在我处理完之前是不会别的人改变的。

    这就要求了整个业务过程的互斥。所以我在这里将service改成单例,处理方法添加互斥锁。

    service

    package com.midea.test;
    
    public class ProductService {
        
        private static ProductService productService = new ProductService();
        
        private ProductService() {
            
        }
        
        public static ProductService getInstance() {
            if (productService == null) {
                return new ProductService();
            }
            return productService;
        }
        
        private ProductDao productDao;
    
        public ProductDao getProductDao() {
            return productDao;
        }
    
        public void setProductDao(ProductDao productDao) {
            this.productDao = productDao;
        }
    
        public synchronized void process() {
            int n = productDao.getNum();
            System.out.println(Thread.currentThread().getId()+",before:"+n);
            productDao.setNum(n+1);
            System.out.println(Thread.currentThread().getId()+",after:"+productDao.getNum());
            
        }
    
        
        
    }

    测试方法

            
            for (int i=0; i<10; i++) {
                Thread t = new Thread(){
    
                    @Override
                    public void run() {
                        ProductService service = ProductService.getInstance();
                        System.out.println(service.hashCode());
                        ProductDao dao = new ProductDao();
                        service.setProductDao(dao);
                        service.process();
                    }
                    
                };
                t.start();
                
            }
            
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println("最后结果:"+Data.getInstance().getNum());
        

    结果:

    发现service的hashcode一致,同一个service实例,最后结果为20,与预期一致。

    19627754
    19627754
    19627754
    19627754
    19627754
    11,before:10
    11,after:11
    10,before:11
    10,after:12
    14,before:12
    14,after:13
    12,before:13
    12,after:14
    13,before:14
    13,after:15
    19627754
    19627754
    19,before:15
    19,after:16
    19627754
    17,before:16
    17,after:17
    18,before:17
    18,after:18
    19627754
    19627754
    15,before:18
    15,after:19
    16,before:19
    16,after:20
    最后结果:20

    嗯,准备按这个思路修改bug去。不过很可能处理时间很长,这也是没办法的。

  • 相关阅读:
    Mvc+三层(批量添加、删除、修改)
    js中判断复选款是否选中
    EF的优缺点
    Git tricks: Unstaging files
    Using Git Submodules
    English Learning
    wix xslt for adding node
    The breakpoint will not currently be hit. No symbols have been loaded for this document."
    Use XSLT in wix
    mfc110ud.dll not found
  • 原文地址:https://www.cnblogs.com/yun965861480/p/6549927.html
Copyright © 2011-2022 走看看