一.现网问题描述
现网在同一文件分片上传的过程中发生创建目录失败,抛出异常
二,定位问题
从日志中能够看出上传分片的顺序是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();
}
}
}
经过验证,并发创建文件时,不会出现抛异常的场景