• 并发问题


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

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

    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去。不过很可能处理时间很长,这也是没办法的。

  • 相关阅读:
    mysql 数据库的简单操作 2
    mysql简单操作,增删查改.
    当mysq启动时出现错误1067时应如何解决
    JS中 逻辑或 || 逻辑与 && 的使用方法总结
    编写一段程序,运行时向用户提问“你考了多少分?(0~100)”,接受输入后判断其等级并显示出来。判断依据如下:等级={优 (90~100分);良 (80~89分);中 (60~69分);差 (0~59分);}
    IF的使用
    第一个输出程序 Console.WriteLine
    Day2_and_Day3 文件操作
    linux安装VLAN,系统怎么划分VLAN打标签上交换机
    Python3.5+selenium(11)脚本模块化&参数化
  • 原文地址:https://www.cnblogs.com/yun965861480/p/6549927.html
Copyright © 2020-2023  润新知