首页 > 其他分享 >模板方法中的线程安全问题

模板方法中的线程安全问题

时间:2023-05-05 11:56:13浏览次数:31  
标签:sheet rowIndex void 安全 线程 data public 模板

1、线程安全?

是否存在临界区,共享的变量,会被不同线程写入

那么模板方法里面基类的成员变量或者方法就会存在线程安全问题

2、excel 

 

AbstractExcelSheet

业务数据和excel 逻辑 解耦

让data 可以 在service 层之间set进来

这样excel的相关类不用添加到 spring 容器中

 

public abstract class AbstractExcelSheet<T> {
    private XSSFWorkbook workbook;

    private XSSFSheet sheet;

    /**
     * 写入数据
     */
    private List<T> data;

    public void setData(List<T> data) {
        this.data = data;
    }

    /**
     * 获取当前类的sheet对象
     *
     * @return sheet对象
     */
    public XSSFSheet getSheet() {
        return sheet;
    }

    /**
     * 设置sheet对象
     *
     * @param sheet sheet对象
     */
    public void setSheet(XSSFSheet sheet) {
        this.sheet = sheet;
    }

    /**
     * 获取所属的excel对象
     *
     * @return excel对象
     */
    public XSSFWorkbook getWorkbook() {
        return workbook;
    }

    /**
     * 设置excel对象
     *
     * @param workbook excel对象
     */
    public void setWorkbook(XSSFWorkbook workbook) {
        this.workbook = workbook;
    }

    /**
     * 创建sheet页基本信息
     */
    public abstract void createSheet();

    /**
     * 在子类重写
     *
     * @return 标题列
     */
    public abstract List<String> getTitles();

    /**
     * 生成sheet标题列,此方法不必重写
     */
    public void createTitleRow() {
        List<String> titles = getTitles();
        // 得到行
        XSSFRow titleRow = getSheet().createRow(0);
        for (int i = 0; i < titles.size(); i++) {
            XSSFCell cell = titleRow.createCell(i);
            cell.setCellStyle(ExportExcelUtil.getTitleStyle(getWorkbook()));
            cell.setCellValue(titles.get(i));
        }
        // 设置行高
        titleRow.setHeight((short) 460);
    }

    /**
     * 添加导出excel的内容
     *
     * @param data 导出数据
     */
    public abstract void createDataRow(List<T> data);

    /**
     * writeSheetData
     */
    public void writeSheetData() {
        // 创建表单 sheet
        createSheet();
        // sheet 设置表头内容(第一行内容)
        createTitleRow();
        // 从数据库取数并写到文件中
        createDataRow(data);
    }

    /**
     * 写入一行 sheet 数据
     *
     * @param rowIndex sheet 写入 行索引
     * @param data sheet 实体数据
     * @param enumValues sheet 表头标题
     * @param <S> 泛型
     */
    protected <S> void writeRowData(int rowIndex, S data, SheetTitleEnum[] enumValues) {
        XSSFRow row = getSheet().createRow(rowIndex);
        int colIndex = 0;
        XSSFCell cell = row.createCell(colIndex);
        for (SheetTitleEnum enumValue : enumValues) {
            String cellValue = ExportExcelUtil.getCellValue(data, enumValue);
            cell.setCellValue(cellValue);
            cell = row.createCell(++colIndex);
        }
    }
}

BusiPackageResultExcelSheet

业务知识包检查结果.xlsx 业务知识包检查结果 sheet

 

public class BusiPackageResultExcelSheet<T> extends AbstractExcelSheet<T> {
    private final static String SHEET_NAME = "业务知识包检查结果";

    @Override
    public void createSheet() {
        this.setSheet(this.getWorkbook().createSheet(SHEET_NAME));
    }

    @Override
    public List<String> getTitles() {
        return BusiPackageResultSheetTitleEnum.titles;
    }

    @Override
    public void createDataRow(List<T> data) {
        // 表头 rowIndex = 0, 所以 rowIndex = 1
        int rowIndex = 1;
        SheetTitleEnum[] enumValues = BusiPackageResultSheetTitleEnum.values();
        for (T dataEntry : data) {
            // 写入行数据
            writeRowData(rowIndex++, dataEntry, enumValues);
        }
    }
}

BusiPkgRuleResultExcelSheet

业务知识包检查结果.xlsx 规则检查结果 sheet
public class BusiPkgRuleResultExcelSheet<T> extends RuleResultExcelSheet<T> {
    @Override
    public void createDataRow(List<T> data) {
        // 表头 rowIndex = 0, 所以 rowIndex = 1
        int rowIndex = 1;
        for (T dataEntry : data) {
            // 写入行数据
            writeRowData(rowIndex++, dataEntry, RuleResultSheetTitleEnum.values());
        }
    }
}

 

RuleResultExcelSheet

规则检查结果.xlsx 规则检查结果 sheet
public class RuleResultExcelSheet<T> extends AbstractExcelSheet<T> {
    private final static String SHEET_NAME = "规则检查结果";

    @Override
    public void createSheet() {
        this.setSheet(this.getWorkbook().createSheet(SHEET_NAME));
    }

    /**
     * 表头内容
     *
     * @return 表头内容
     */
    @Override
    public List<String> getTitles() {
        return RuleResultSheetTitleEnum.titles;
    }

    @Override
    public void createDataRow(List<T> data) {
        // 表头 rowIndex = 0, 所以 rowIndex = 1
        int rowIndex = 1;
        SheetTitleEnum[] enumValues = RuleResultSheetTitleEnum.values();
        for (T dataEntry : data) {
            // 写入行数据
            writeRowData(rowIndex++, dataEntry, enumValues);
        }
    }
}

上面的设计 大部分的方法都是在基类实现了

当excel的表头不一样,是在子类实现的

3、线程安全问题点

所有的成员变量都有可能被其他线程争抢,

比如 线程1 setData data1 

但是此时如果线程1 excel 还没导出成功,

线程2进来了 setData data2

把线程1的 data 覆盖了

其实还有很多线程问题,因为多线程是不可控的

4、解决

 service 在的调用 excel 实现类的时候,变成局部变量

在单应用中 合理运用 synchronized 、ReentrantLock、 ThreadLocal 原子应用

分布式 合理运用 redis 锁

两种运用,注意死锁问题

标签:sheet,rowIndex,void,安全,线程,data,public,模板
From: https://www.cnblogs.com/linzm14/p/17373666.html

相关文章

  • 6-2 数组排序输出(函数模板)
    对于输入的每一批数,按从小到大排序后输出。一行输入为一批数,第一个输入为数据类型(1表示整数,2表示字符型数,3表示有一位小数的浮点数,4表示字符串,0表示输入结束),第二个输入为该批数的数量size(0<size<=10),接下来为size个指定类型的数据。输出将从小到大顺序输出数据。函数接口定义:sor......
  • 类模板。。。对象数组
    #include<bits/stdc++.h>usingnamespacestd;template<classT>classAAA{      Ta,b;   public:      AAA(T_a,T_b):a(_a),b(_b){};      Tsum(){         returna+b;      }      Tcha();};template<......
  • 文件外发怕泄密 如何做到外发文件安全管控?
    随着企业信息化技术的发展,以及近年这种数据泄密事件频发,越来越多的企业,开始关注数据安全。数据安全包括很多方面,其中文件的外发安全,是经常容易受到忽视的。企业日常运营中,与外部合作伙伴、供应商之间需要频繁的进行文件的交互,尤其是制造型企业,需要外发图纸、设计稿等等。很多企......
  • get()和set()方法在保护类安全性上的意义
    1、起因如果为一个private变量设置了get()和set()方法,不就是相当于其为public变量吗?这样做是不是过于繁琐了?如果对形如下方的简单代码而言,可以说是上面的疑惑是对的publicclassSimpleGetAndSet{privateintn;publicSimpleGetAndSet(intn){this.n=......
  • kysely typescript 类型安全的sql 查询构建包
    typescript目前已经有不少方便的sql工具了,kysely是一个类型安全方便的sql查询构建工具对于使用typescript开发node服务的是个一个不错的选择,值得试用参考资料https://github.com/kysely-org/kyselyhttps://typeorm.io/https://github.com/typeorm......
  • 极简爬虫通用模板
    网络爬虫的一般步骤如下:1、确定爬取目标:确定需要爬取的数据类型和来源网站。2、制定爬取策略:确定爬取哪些网页、如何爬取和频率等。3、构建爬虫程序:使用编程语言(如Python)实现爬虫程序,通过HTTP请求获取网页内容,并进行解析和处理。4、数据存储:将爬取到的数据存储到数据库或文件......
  • 5月4日:unordermap/set,哈希以及哈希常用的拉链法,开放地址法,以及模板的特化相关应用
    起处较为流行的数据储存方式为树形结构,再加上红黑树等优秀数据结构的发展,直到今天二叉平衡搜索树也经常被应用在各种方面,但是c++库里面还有两个与map/set很像的容器unorderedmap,他们的调用与普通的map几乎一样,有着非常优秀的查找时间复杂度,只是不能像二叉树哪样层序遍历得到顺序的......
  • 模板
    6-1有序数组(类模板)单位 福州大学实现一个类模板,它可以接受一组数据,能对数据排序,也能输出数组的内容。每行输入的第一个数字为0,1,2或3:为0时表示输入结束;为1时表示将输入整数,为2时表示将输入有一位小数的浮点数,为3时表示输入字符。如果第一个数字非0,则接下来将输入......
  • 打卡 有序数组(类模板)
    实现一个类模板,它可以接受一组数据,能对数据排序,也能输出数组的内容。每行输入的第一个数字为0,1,2或3:为0时表示输入结束;为1时表示将输入整数,为2时表示将输入有一位小数的浮点数,为3时表示输入字符。如果第一个数字非0,则接下来将输入一个正整数,表示即将输入的数据的数量。从每行......
  • C语言多线程
    线程按照其调度者可以分为用户级线程和核心级线程两种 用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行选择决定,在运行时不需要特定的内核支持; 我们常用基本就是用户级线程,所以就只总结一下POSIX提供的用户级线程接口; 基本线程操作相关的函数: 1......