File.mkdirs()現網併發創建失敗

一.現網問題描述

現網在同一文件分片上傳的過程中發生創建目錄失敗,拋出異常

二,定位問題

從日誌中能夠看出上傳分片的順序是1,2,0,3,4

第二個分片請求上傳首先到達進行創建目錄

第三個分片請求上傳進行創建目錄失敗

 

看代碼進行分析

已經很明顯啦,

導致的問題是分片上傳的過程中併發上傳分片,同時創建相同目錄,導致在下面代碼紅色標記的地方發生併發。

file.mkdirs方法如果目錄已經存在,則返回false;如果目錄不存在,創建成功,返回false

三.修改驗證

修改代碼爲

併發驗證

 package testJVm;

import java.io.File;
import java.util.concurrent.CountDownLatch;

public class TestDir
{
    
    public static void main(String[] args)
        throws InterruptedException
    {
        CountDownLatch countDown = new CountDownLatch(1);
        CountDownLatch await = new CountDownLatch(50); // 依次創建並啓動處於等待狀態的5個MyRunnable線程
        for (int i = 0; i < 50; ++i)
        {
            new Thread(new MyRunnable(countDown, await)).start();
        }
        System.out.println("用於觸發處於等待狀態的線程開始工作......");
        System.out.println("用於觸發處於等待狀態的線程工作完成,等待狀態線程開始工作......");
        countDown.countDown();
        await.await();
        System.out.println("Bingo!");
    }
    
    public static String creatDIRS(String path)
    {
        File file = new File(path);
        if (file.exists())
        {
            System.out.println("file is exist, path = " + path);
            return path;
        }
        
        if (!file.mkdirs())
        {
            System.out.println("file mkdirs is fail, path = " + path);
            if (!file.exists())
            {
                System.out.println("file make director error");
            }
            else
            {
                System.out.println("OK");
            }
        }
        return path;
    }
    
}

package testJVm;

import java.util.concurrent.CountDownLatch;

public class MyRunnable implements Runnable
{
    private final CountDownLatch countDown;
    
    private final CountDownLatch await;
    
    private final String path ="c://opt//hua//wei"; 
    
    public MyRunnable(CountDownLatch countDown, CountDownLatch await)
    {
        this.countDown = countDown;
        this.await = await;
    }
    
    public void run()
    {
        try
        {
            countDown.await();// 等待主線程執行完畢,獲得開始執行信號...
            System.out.println("處於等待的線程開始自己預期工作......");
            TestDir.creatDIRS(path);
            await.countDown();// 完成預期工作,發出完成信號...
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

經過驗證,併發創建文件時,不會出現拋異常的場景

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章