生产中遇到的Java多线程问题

1. 问题场景:前几天一位同事分享了一段代码,这段代码在线上偶尔会报空指针异常,虽然是一个简单的NullPointerException,却是一个很不容易发现的多线程问题导致的,我们一起先来看下代码(这是我复原的测试代码,并非和生产一致,但整体逻辑是一样的):

public class TestSingleton {

    private static volatile TestSingleton testSingleton = null;

    static Map<String, String> idCard;

    private TestSingleton() {}

    public static TestSingleton init() {

        if (testSingleton == null) {

            synchronized (TestSingleton.class) {

                if (testSingleton == null) {

                    testSingleton = new TestSingleton();

                    idCard = new HashMap<>();

                    idCard.put("aa", "bb");
                }
            }
        }

        return testSingleton;

    }

    public String getIdCard() {

        return idCard.get("aa");

    }


    public static void main(String[] args) {

        TestSingleton testSingleton = TestSingleton.init().getIdCard();    

    }
}

整体来看这位仁兄是实现了一个单例类,看样子没什么问题,只是多了一个Map来实例化并设置一些kv值,从逻辑上来没看出有什么毛病,我一开始看到这个代码确实没看出什么问题来。

如果先不看后续的描述,你能看出问题来吗?

静静地观察一分钟...

2. 问题还原分析:通过观察看出是什么问题了吗?如果你立马定位了原因,那么说明你的多线程还是挺扎实的,接下来我们一块来分析一下问题原因。首先我启动main方法执行,没有发现任何问题,多试几次也没问题,但这并不能说明就真正没问题(要不然生产上的问题就没法解释了),因为我现在这样执行main方法是单线程,只能说明这个代码在单线程场景下是没有任何问题的。现在我将main方法改成多线执行:

public static void main(String[] args) {

        int n = 10;

        CountDownLatch countDownLatch = new CountDownLatch(n);

        ExecutorService executorService = Executors.newFixedThreadPool(n);

        for (int i = 0; i < n; i++) {

            executorService.execute(() -> {

                TestSingleton.init().getIdCard();

                countDownLatch.countDown();

            });

        }

        try {

            //等待所有线程执行完毕

            countDownLatch.await();

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        //统计一下执行情况,看是否都执行完成

        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;

        System.out.println("总任务数:" + threadPoolExecutor.getTaskCount());

        System.out.println("正在执行任务数字:" + threadPoolExecutor.getActiveCount());

        System.out.println("完成任务数:" + threadPoolExecutor.getCompletedTaskCount());

    }

接下来我使用线程池,启动10个线程试试看能否还原出报NullPointException,多执行几次发现确实报出了空指针,

/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=52108:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/charse
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值