场景描述
我们将要模拟指定一个文件目录,将该目录的所有所有的文件上传到ftp服务器上
我们知道获取ftp连接与读取目录中所有文件都是比较耗时的,如果可以同时进行是最好的,我们可以使用多线程来获取连接,但两个线程哪个快无法保证,如何保证当连接创建成功后才开始执行上传文件呢,就可以使用承诺模式
一. FTPConnectionUtil
调用者可以通过getPromise()方法获取Ftp连接承诺者对象FutureTask<FTPConnectionUtil>,我们假设获取连接时间为5秒
public class FTPConnectionUtil {
private Exception exception;
private FTPConnectionUtil(){
//防止通过暴力反射破坏单例
if(InFTPConnectionUtil.connectionUtil != null){
throw new RuntimeException("单例已经存在!");
}
}
public static FTPConnectionUtil newInstance(){
return InFTPConnectionUtil.connectionUtil;
}
/**
* 内部类单例,只有调用时才会加载,既避免了懒汉式浪费资源,又避免了饿汉式安全问题
*/
private static class InFTPConnectionUtil{
private final static FTPConnectionUtil connectionUtil = new FTPConnectionUtil();
}
/**
* 构造方法私有,根据此方法获取FutureTask承诺,通过多线程建立连接,然后通过FutureTask.get()方法获取泛型<T>,
* 可以通过isDone方法判断多线程是否执行完毕
* 可以在泛型实体里接受异常属性,通过获取属性判断建立连接过程是否正常</>
* @return
*/
public static FutureTask<FTPConnectionUtil> getPromise(){
Callable<FTPConnectionUtil> callable = new Callable() {
@Override
public Object call() throws Exception {
FTPConnectionUtil ftpConnectionUtil = FTPConnectionUtil.newInstance();
return ftpConnectionUtil.doFtpConnection(ftpConnectionUtil);
}
};
FutureTask<FTPConnectionUtil> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
return futureTask;
}
private FTPConnectionUtil doFtpConnection(FTPConnectionUtil util){
try {
System.out.println("---------建立连接开始");
for (int i = 1; i <= 5; i++) {
Thread.sleep(1000);
System.out.println("-----建立连接"+i+"秒!");
}
System.out.println("---------建立连接完成");
}catch (Exception e){
util.exception = e;
}
return util;
}
public void upload(File file){
System.out.println(file.getName() + "上传完成!");
}
public Exception getException() {
return exception;
}
private void setException(Exception exception) {
this.exception = exception;
}
public void closeConnection(){
System.out.println("关闭连接!");
}
}
二. 上传方法服务
我们假设读取文件瞬间完成,又因建立连接需要5秒时间,此时应该等待获取连接后依次上传文件,所以我们通过无限循环调用承诺者对象FtpPromise.isDone()判断是否完成连接,如果连接完成开始上传文件。此处我们可以通过次数或时间来限制最大等待时间
public class UploadToFTP {
FutureTask<FTPConnectionUtil> FtpPromise = FTPConnectionUtil.getPromise();
System.out.println("读取文件开始!");
ArrayList<File> files = new ArrayList<>();
files.add(new File("file1"));
files.add(new File("file2"));
files.add(new File("file3"));
System.out.println("读取文件结束!");
FTPConnectionUtil ftpConnectionUtil = null;
while (true) {
Thread.sleep(1000);
if(FtpPromise.isDone()){
ftpConnectionUtil = FtpPromise.get();
if (ftpConnectionUtil.getException() != null) {
throw ftpConnectionUtil.getException();
}
for (File file : files) {
ftpConnectionUtil.upload(file);
}
break;
}else{
System.out.println("等待");
}
}
ftpConnectionUtil.closeConnection();
}
}
三. 测试方法
public class Run {
public static void main(String[] args) throws Exception {
UploadToFTP uploadToFTP = new UploadToFTP();
uploadToFTP.upload();
}
}
四. 测试结果
读取文件开始!
读取文件结束!
-----建立连接开始
等待
-----建立连接1秒!
等待
-----建立连接2秒!
等待
-----建立连接3秒!
等待
-----建立连接4秒!
等待
-----建立连接5秒!
-----建立连接结束
file1上传完成!
file2上传完成!
file3上传完成!
关闭连接!