多线程调用static方法线程安全问题

本文探讨了在多线程环境下使用静态SimpleDateFormat解析Date字符串引发的线程安全问题,通过分析其Calendar共享机制,提出了使用synchronized、成员变量或ThreadLocal解决策略,并给出了DateUtil类的优化示例。
摘要由CSDN通过智能技术生成

最近在工作中遇到了线程安全的问题,是在一个方法中调用了静态方法解析Date的字符串。

因为 SimpleDateFormat这个类是线程不安全的,所以不能在静态方法中定义全局的成员变量。

@Test
void contextLoads() {
    ExecutorService executorService= Executors.newFixedThreadPool(6);
    for (int i = 0; i < 6; i++) {
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                Date date= DateUtil.ParseDate("20210501");
                System.out.println("子线程"+Thread.currentThread().getName()+date);
            }
        };
        executorService.execute(runnable);
    }
  
}

 

原因:

SimpleDateFormat继承了DateFormat,DateFormat内部有一个Calendar对象的引用,主要用来存储和SimpleDateFormat相关的日期信息

SimpleDateFormat对parse()方法的实现。关键代码如下:

@Override
public Date parse(String text, ParsePosition pos) {
    ...省略中间代码
    Date parsedDate;
    try {
        ...
        parsedDate = calb.establish(calendar).getTime();
    } catch (IllegalArgumentException e) {
       ...
    }

    return parsedDate;
}

establish()的实现如下:

Calendar establish(Calendar cal) {
    ...
    cal.clear();
    for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
        for (int index = 0; index <= maxFieldIndex; index++) {
            if (field[index] == stamp) {
                cal.set(index, field[MAX_FIELD + index]);
                break;
            }
        }
    }
    ...
    return cal;
}


在多个线程共享SimpleDateFormat时,同时也共享了Calendar引用,在如上代码中,calendar首先会进行clear操作,然后进行set操作,在多线程情况下,set操作会覆盖之前的值,而且在后续对日期进行操作时,也可能会因为clear操作被清除导致异常

 解决方法:

1.使用synchronized来保证线程安全。

2.把全局变量换为使用成员变量。

3.使用ThreadLocal

public class DateUtil {
    private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
//    public static synchronized   Date ParseDate(String str){//  方案1,加锁
 public static  Date ParseDate(String str){
        try {
            SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");//方案2,使用成员变量。
            return sf.parse(str); 
          //return simpleDateFormat.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值