Android应用设计之实现多线程框架

Android应用设计之实现多线程框架

做了Android开发满2年了,感觉在开发中用的很多的就是多线程了;由于在现代的计算机中CPU核数越来越多,因此操作系统底层就向多线程方向发展。因此为了跟上时代,开篇就将平时用的比较多的多线程开发原理吧。
本文需要掌握一定的Android基础;比如Handler,Message,Looper等的关系;还需要掌握一些Java线程池的知识,方能更好的理解本文。
架构是本人根据实际开发经验悟出,因此有不完善的地方,希望大家指正。共同学习进步才是我的目的。
首先提出几个问题:
一:多线程,既然是多线程,就是多个运行的程度,那么是不是需要一个可以管理这些的策略。要不太多了,占用资源太多,系统就会变卡。
二:Activity启动只是在他自己的ActivityThread里面,因此启动其他的线程必须在主线程(ActivityThread)里面启动的。因此还有一个主线程和这个线程的交互问题。
三:手机只有一个,因此必定存在线程之间的竞争关系;比如同时读写一个文件;同时等待一个条件;这里面还牵扯到线程的释放问题;如何安全的结束一个线程。同时竞争CPU资源等。
四:最困难的是多线程之间互相等待的问题,比如这个线程等待一个条件;而另一个线程也等待一个条件;如果这个条件永远无法满足,那么就会出现线程饿死问题。
本文就是为了探索多线程在Android APP中的应用;我尽量为大家展示一种简单易懂的,不容易出现问题的设计多线程程序的思路来发挥多线程的优势,而避免多线程带来的不足。
既然是框架,那么解决的就是通用问题;因此本文主要围绕如何管理线程,如何为使用者提供线程,如何最大量的复用已有的线程池,如何在线程之间交互进行一个框架。
第一个出场的就是线程池对象:
java.util.concurrent.ExecutorService
这个对象就是线程池对象:
我们先将线程池的创建和使用接口分开设计,分别设计两个类;
线程池的创建管理类:
核心思想是利用Map集合来管理已经创建的线程池:

/**
*
* @author 徐晔
* @note 获取指定模式的线程池对象
*/
public final class XYTPoolCreater {

public final static int CachedThreadPool=0;
public final static int FixedThreadPoo=1;
public final static int ScheduledThreadPool=2;
public final static int SingleThreadScheduledExecutor=3;

private Map<String, ExecutorService> executorServicemap;
private Map<String, ScheduledExecutorService> scheduledExecutorServicemap;
public static XYTPoolCreater getInstance = new XYTPoolCreater();

private XYTPoolCreater() {
    executorServicemap = new HashMap<String, ExecutorService>();
    scheduledExecutorServicemap = new HashMap<String, ScheduledExecutorService>();
}

/***
 * 创建新的线程池
 *  * @param typeid
 * @param 0:返回一个带缓存的线程池,该池在必要的时候创建线程,在线程空闲60秒后终止线程
 * @param 1:返回一个线程池,该池中的线程数由参数指定
 * @param 2:返回一个执行器,它在一个单一的线程中依次执行各个任务
 ***************************
 * @param corepoolsize
 *            :线程池中线程的数目
 * @param key
 * @param typeid
 * @param corepoolsize
 * @param factory
 */
public synchronized ExecutorService creatnewExecutorService(String key, int typeid,
        int corepoolsize, ThreadFactory factory) {
    ExecutorService service = null;
    boolean flag = false;
    if (key == null) {
        flag = true;
        return service;
    }
    for (String oldkey : executorServicemap.keySet()) {
        if (key.equals(oldkey)) {
            service = executorServicemap.get(oldkey);
            flag = true;
            break;
        }
    }
    if (!flag) {
        service = getExecutorService(typeid, corepoolsize, factory);
        executorServicemap.put(key, service);
    }
    return service;

}

/**
 * 获取已经存在的ExecutorService
 * 
 * @param key
 * @return
 */
public ExecutorService getExecutorService(String key) {
    ExecutorService service = null;
    if (key != null) {
        service = executorServicemap.get(key);
    }
    return service;
}

/**
 * 创建新的周期性任务池
 * 
 * @param key
 * @param typeid
 * @param corepoolsize
 * @param factory
 */
public synchronized ScheduledExecutorService creatnewScheduledExecutorService(
        String key, int typeid, int corepoolsize, ThreadFactory factory) {
    ScheduledExecutorService service = null;
    boolean flag = false;
    if (key == null) {
        flag = true;
        return service;
    }
    for (String oldkey : scheduledExecutorServicemap.keySet()) {
        if (key.equals(oldkey)) {
            service = scheduledExecutorServicemap.get(oldkey);
            flag = true;
            break;
        }
    }
    if (!flag) {
        service = getScheduledExecutorService(typeid, corepoolsize, factory);
        scheduledExecutorServicemap.put(key, service);
    }
    return service;
}

/**
 * 获取以及存在的ScheduledExecutorService
 * 
 * @param key
 * @return
 */
public ScheduledExecutorService getScheduledExecutorService(String key) {
    ScheduledExecutorService service = null;
    if (key != null) {
        service = scheduledExecutorServicemap.get(key);
    }
    return service;
}

/**
 * 创建线程池的工厂
 * 
 * @param typeid
 * @param XYTPool.CachedThreadPool:返回一个带缓存的线程池,该池在必要的时候创建线程,在线程空闲60秒后终止线程
 * @param XYTPool.FixedThreadPoo:返回一个线程池,该池中的线程数由参数指定
 ***************************
 * @param corepoolsize
 *            :线程池中线程的数目
 */
private ExecutorService getExecutorService(int typeid, int corepoolsize,
        ThreadFactory factory) {
    ExecutorService mService = null;
    if (corepoolsize < 1) {
        corepoolsize = 1;
    }
    if (typeid < 0 || typeid > 2) {
        typeid = 0;
    }
    switch (typeid) {
    case CachedThreadPool:
        if (factory != null) {
            mService = Executors.newCachedThreadPool(factory);
        } else {
            mService = Executors.newCachedThreadPool();
        }

        break;
    case FixedThreadPoo:
        if (factory != null) {
            mService = Executors.newFixedThreadPool(corepoolsize, factory);
        } else {
            mService = Executors.newFixedThreadPool(corepoolsize);
        }
        break;
    }
    return mService;
}



/**
 * 预定执行或者重复执行的线程池接口
 * 
 * @param typeid
 * @param XYTPool.ScheduledThreadPool:返回一个线程池,它使用给定的线程数来调度任务
 * @param XYTPool.SingleThreadScheduledExecutor1:返回一个执行器,它在一个单线程中调度任务
 */
private ScheduledExecutorService getScheduledExecutorService(int typeid,
        int corepoolsize, ThreadFactory factory) {
    if (corepoolsize < 1) {
        corepoolsize = 1;
    }
    ScheduledExecutorService mService = null;
    if (typeid > 1 || typeid < 0) {
        typeid = 0;
    }
    switch (typeid) {
    case ScheduledThreadPool:
        if (factory != null) {
            mService = Executors.newScheduledThreadPool(corepoolsize,
                    factory);
        } else {
            mService = Executors.newScheduledThreadPool(corepoolsize);
        }
        break;
    case SingleThreadScheduledExecutor:
        if (factory != null) {
            mService = Executors.newSingleThreadScheduledExecutor(factory);
        } else {
            mService = Executors.newSingleThreadScheduledExecutor();
        }
        break;
    }
    return mService;
}

}

接下来我们需要设计几个接口以满足线程池中添加任务的需求:

/**
 * @author 徐晔
 * 异步线程执行之前需要执行的方法
 */
public  interface XYdoBefore {
    /**在执行之前*/
    public void before(int taskid);
 }
/**
 *
 @author 徐晔
 * @param <V>
 * @note 执行异步任务得到的回调接口
 */
public interface XYgetresult<V> {
    /**
     * 执行完成,得到返回结果
     * @param <V>
     */
    public void onfinish(int id, V v);
}
/**
 * 
* @author 徐晔
 * @note 执行没有返回参数的异步任务方法
 */
public interface XYInBack {
    /**在异步线程中执行的方法体*/
     public void doinbackground();
}
/**
* 
 * @author 徐晔
 * @param <V>
 * @note 执行有返回参数的异步任务方法
 */
 public interface XYInBackwithResult<V> {
    /**在异步线程中执行的方法体
     * @param <V>*/
     public  V doinbackground();
}
以上四个是我简单

设计的执行异步任务的方法接口,里面有简单的标识id,有简单的值字段来代表参数。
下面是我具体的给线程池提交参数的类:

/**
* @author 徐晔
* @note 线程池配置类
*/
public final class XYTPool {

/**
 * @param <V>
 * 进行有返回参数异步任务
 * @throws Exception
 * @throws
 */
public static <V> void dobackWithResult(final ExecutorService pool,
        final int id, final XYInBackwithResult<V> dInbackground,
        final XYgetresult<V> getResult){
    pool.submit(new Runnable() {
        @Override
        public void run() {
            getResult.onfinish(id, dInbackground.doinbackground());
        }
    });
}

/**
 * 执行没有返回参数的任务
 * 
 * @param pool
 * @param id
 * @param dInbackground
 * @throws Exception
 */
public static void dobackWithoutResult(final ExecutorService pool,
        final XYInBack dInbackground){
    pool.submit(new Runnable() {
        @Override
        public void run() {
            dInbackground.doinbackground();
        }
    });
}

/**
 * 执行定期任务
 * @param <V>
 * 
 * @param typeid
 * @param 0:预定在指定时间之后执行任务(1次)
 * @param 1:预定在初始的指定时间之后周期性的执行任务,周期是delay
 * @param 2:预定在初始的指定时间之后周期性的执行任务,在一次调用完成和下一次调用开始之间有长度为delay的延迟
 * 
 */
public static <V> void schedule(final ScheduledExecutorService service,
        int typeid, final XYInBackwithResult<V> task,
        long initialdelay, long delay, TimeUnit unit) {
    if (typeid < 0 || typeid > 2) {
        typeid = 0;
    }
    switch (typeid) {
    case 0:
        service.schedule(new Runnable() {
            @Override
            public void run() {
                task.doinbackground();
            }
        }, delay, unit);
        break;
    case 1:
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                task.doinbackground();
            }
        }, initialdelay, delay, unit);
        break;
    case 2:
        service.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                task.doinbackground();
            }
        }, initialdelay, delay, unit);
        break;
    }

}

/**
 * 关闭服务
 */
public static void shutdown(ExecutorService service) {
    if (service != null && !service.isShutdown()) {
        service.shutdown();
    }
}

}
好了,有了这么几个,简单的线程池管理类,创建类和实现接口对象都有了;
稍微完善一下就可以直接用以上三个类来实现异步任务管理了;但是在Android中,我们还需要实现线程之间值的传递;如下
我设计一个通用的Task类:
/**
* @param
* @param handler:
* 推荐直接传递 new Handler(Looper);
* @param before
* :执行异步线程之前执行的方法
* @param getResult
* :得到异步任务执行结果得到的线程 可以完成大部分的任务,类似于异步请求网络,异步查询数据库,普通的异步任务都可以继承该类来进行实现
*/
public abstract class XYAsynBaseTask implements XYgetresult,
XYdoBefore,XYInBackwithResult {
private XYgetresult mResult;
private XYdoBefore before;
private Handler handler;

/**
 * @param mLooper
 *            :Loop对象必须在调用前初始化好,
 *            比如Looper.prepareMainLooper()(Activity主线程);或者Looper.prepare();
 *            调用之后必须执行Looper.loop();方法
 * @param before
 *            :执行异步线程之前执行的方法
 * @param getResult
 *            :得到异步任务执行结果得到的线程
 */
public XYAsynBaseTask(Handler handler, XYdoBefore before,XYgetresult<V> mResult) {
    this.handler=handler;
    this.before = before;
    this.mResult=mResult;
}

public void execute(int id) throws Exception {
    XYAsynBaseTask.this.before.before(id);
    XYTPool.dobackWithResult(XYTPoolCreater.getInstance
            .creatnewExecutorService(XYAsynConsts.HTTPTHREAD_KEY, 1, 5,
                    null), id, this, this);
}

@Override
public void onfinish(final int id,final V v) {
    handler.post(new Runnable() {
        @Override
        public void run() {
            mResult.onfinish(id, v);
        }
    });
}

@Override
public abstract V doinbackground();

}
我们在这个基类里通过Android 自己的Handler机制实现了线程之间的交互;执行了线程运行之前需要执行的方法,线程运行得到结果后,将结果返回给Handler所在的线程;为什么传递参数用Handler,开始用Looper,然后new一个Handler对象,但是后面感觉这样貌似浪费了很多Handler对象,所以本人觉得还是传递Handler的好,在主线程new一次;将线程体中需要执行的方法延迟到子类实现;有一点控制反转的意思;
看到这里,一个多线程的框架就此完成。至于如何使用,我相信看懂的人没有不会使用的。
写到最后,这个只是一个简单的多线程框架,用了Runnable对象,无法跟踪线程的执行。如果想要保持线程的跟踪,可以使用Callable
对象和FutureTask对象来实现;但是要注意阻塞,本人不建议用FutureTask来得到结果,因为那个获取结果的方法是一个阻塞式方法;本文抛砖引玉,希望可以给大家提供一个思路。至于最上面提到的问题,就看大家各自的设计能力了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值