多线程设计模式——Promise(承诺)模式

这些都是根据我最近看的《Java实战指南多线程编程(设计模式篇)》所得整理。

模式名称

Promise(承诺)模式

模式面对的问题

有的方法会比较耗时,可以让耗时操作在其他线程中进行,然后调用方可以执行其他操作,需要的时候再去耗时操作的结果这就是获得一个线程的承诺,它会做好这个耗时操作。

解决思路

在这个方法中,客户端代码调用某个异步方法锁得到的返回值仅是一个凭据的对象。凭借这个对象,客户端代码可以获取异步方法相应的真正任务的执行结果

Created with Raphaël 2.1.0 Client Client Promisor Promisor promise promise promist promist 1compute() 2create 3 4getResult() 5

例子代码

某系统的一个数据同步模块需要将一批本地文件才上传到指定的目标FTP服务器上,这些文件是根据页面中的输入条件查询数据库的相应记录生成的,在讲文件上传到目标服务器之前需要多FTP客户端实例进行初始化。
线程代码

public class DataSynTask implements Runnable{
    private final Map<String,String>taskParameters;
    puclic DataSyncTask(Map<String,String>taskParameters){
        this.taskParameters = taskParameters;
    }

    @Override
    public void run(){
        String ftpServer = taskParameters.get("server");
        String ftpUserName = taskParameters.get("userName");
        String password = taskParameters.get("password");

        //先开始初始化FTP客户端实例
        Future<FTPClientUtil>ftpClientUtilPromise = FTPClientUtil.newInstance(
                ftpServer, ftpUserName, password);
        //查询数据库生成本地文件
        generateFilesFromDB();

        FTPClientUtil ftpClientUtil = null;
        try{
            //获取初始化完毕的FTP客户端实例
        }catch(InterruptedExeception e){
            ;
        }catch(ExecutionEcception e){
            throw new RuntimeException(e);
        }

        //上传文件
        uploadFiles(ftpClientUtil);

        //忽略其他和设计模式无关的代码
    }

    private void uploadFiles(FTPClientUtil ftpClientUtil){
        Set<File>files = retrieveGeneratedFiles();
        for(File file:files){
            try{
                ftpClientUtil.upload(file);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }

    private Set<File> retrieveGeneratedFiles(){
        Set<File>files = new HashSet<File>();
        //忽略其他和设计模式无关的代码
        return files;
    }
}

FTP客户端代码

//模式角色:Promise.Pfomisor、Promise.Result
public class FTPClientUtil {
    private final FtpClient ftp = new FTPClient();
    private final Map<String,Boolean>dirCreateMap = new HashMap<String,Boolean>();

    private FTPClientUtil(){

    }

    //模式角色Promise.Promisor.compute
    public static Future <FTPClientUtil>newInstance(final String ftpServer,
            final String username,final String password){
        Callable<FTPClientUtil>callable = new Callable<FTPClientUtil>(){
            @Override
            public FTPClientUtil call() throws Exception{
                FTPClientUtil self = new FTPClientUtil();
                self.init(ftpServer,username,password);
                return self;
            }
        };
        //task相当于模式角色:Promise.TaskExecutor
        final FutureTask<FTPClientUtil> task = new FutureTask<FTPClientUtil>(callable);
        //下马这行代码与本案例的实际代码并不一直,这是为了讨论方便。
        //下面新建的线程相当于模式角色:Promise.TaskExecutor
        new Thread(task).start();
        return task;
    }

    private void init(String ftpServer,String userName,String password)throws Exception{
        FTPClientConfig config = new FTPClientConfig();
        ftp.configure(config);

        int reply;
        ftp.connect(ftpServer);

        System.out.print(ftp.getReplyString());

        reply = ftp.getReplyCode();

        if(!FTPReply.isPofitiveCompletion(reply)){
            ftp.disconnect();
            throw new Runtime Exception("FTP server refused connection.");
        }
        boolean isOK = ftp.login(userName, password);
        if(isOK){
            System.out.println(ftp.getReplyString());
        }else{
            throw new RuntimeException("Failed to login." + ftp.getReplyString());
        }

        reply = ftp.cwd("`/subspsync");
        if(!FTPReply.isPositiveCompletion(reply)){
            ftp.disconnect();
            throw new RuntimeException("Failed to change working directory.reply:"+reply);
        }else{
            System.out.println(ftp.getReplyString());
        }
        ftp.setFileType(FTP.ASCOO_FILE_YPE);
    }

    public void upload(File file) throws Exception{
        InputStream dataIn = new BufferedInputStream(new FileInputStream(file),1024*8);
        boolean isOK;
        String dirName = file.getParentFile().getName();
        String fileName =dirName= '/'+file.getName();
        ByteArrayInputStream checkFileInputStream = new ByteArrayInputStream("".getBytes());

        try{
            if(!dirCreateMap.containsKey(dirName)){
                ftp.makeDirectory(dirName);
                dirCreateMap.put(dirName, null);
            }
            try(
                    isOK = ftp.storeFile(fileName.dataIn);
                )catch(IOException e){
                    throw new RuntimeException("Failed to upload"+file,e);
                }
            if(isOK){
                ftp.storeFile(fileName+".c",checkFileInputStream);
            }else{
                throw new RuntimeException("Failed to upload "+file+",reply:"+
                        ","+ftp.getReplyString());
            }
        }finally{
            dataIn.close();
        }
    }

    puclic void disconnect(){
        if(ftp.isConnected()){
            try{
                ftp.disconnect();
            }catch(IOException ioe){
                //什么也不做
            }
        }
    }
}

模式需要注意的问题

异步方法的异常处理
轮询
异步任务的执行

模式评价

承诺模式能够有效的讲耗时操作与需要尽快完成的操作有效分离,大大的提高了代码的利用率

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值