? ? ? ?开发中遇到的问题:看到项目先前实现的代码,有一个逻辑处理,要完成两个界面的切换,而且这个两个界面的切换会共同设置系统的同一个资源的状态,且设置状态的操作(系统中间件已经做了互斥)比较耗时。先前的代码采用了新建线程来设置资源状态来保证主线程不被阻塞。这就出现了一个问题,如果频繁操作切换的话,就会出现系统资源的状态错乱。
? ? ? ?应用调用:
Thread call state(true);
Thread call state(false);
Thread call state(true);
Thread call state(false);
Thread call state(true);
...
Thread call state(true);
? ? 实际执行结果:
Thread run state(true);
Thread run state(false);
Thread run state(true);
Thread run state(true);
Thread run state(false);
...
Thread run state(false); or Thread run state(true);
? ? ? ? 执行结果可以看出,在频繁调用的时候就出现与调用顺序不对应的问题,调用结束的结果可能会是错误的。
? ??
? ? ? ? 究其原因是因为只考虑了耗时操作采用线程来处理,没有对线程进行管理,造成一个操作结束后,其他等待的线程抢占运行,结果肯定会出现不对应调用的情况。
?
? ? ? ?解决方法:
? ? ? ?对于状态这种设置的处理,优先要保证状态的正确性,如果在执行true的时候,又调用设置false,再调用设置true。最终结果会是true。那么在执行第一次true的时候,来了两个操作,可以选择丢弃中间设置false的操作,来提高响应效率和保证结果正确。
? ? ? ?另外线程的组织管理,没有比线程池好的。
? ? 频繁调用帮助类: ?
class="java">/** * 如果你遇到这种场景:应用需要频繁的调用两个互斥的耗时操作,而且要保证效率与结果正确的话,这个帮助类对于你可能会有用。 * Created by leonhover on 13-12-11. */ public class FrequencyTaskHelper { /** * 线程池 */ private ThreadPoolExecutor threadPool = null; /** * 任务队列,大小为1 */ private ArrayBlockingQueue queue = new ArrayBlockingQueue<Runnable>(1); public FrequencyTaskHelper() { //创建线程池,只有一个线程在运行,采用DiscardOldestPolicy机制(采用其他也可以,因为用不到,我们手动清空任务队列) threadPool = new ThreadPoolExecutor(1, 1, 50, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy()); } /** * 在线程池中执行操作,不一定被执行 * * @param runnable 操作任务 */ public void execute(Runnable runnable) { //清空任务队列 queue.clear(); //在线程池中执行,如果没有任务运行则执行,要不就排队,排队后又可能被丢弃。 threadPool.execute(runnable); } }
? ? 测试类
/** * 测试任务,任务延迟有20毫秒 */ public static class TestOption implements Runnable { private String name = null; public TestOption(String str) { name = str; } @Override public void run() { System.out.println("Task " + name + " start "); System.out.println("Task " + name + " executed!"); try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task " + name + " end "); } } //程序入口 public static final void main(String[] args) { System.out.println("Start"); FrequencyTaskHelper helper = new FrequencyTaskHelper(); for (int i = 0; i < 100000; i++) { TestOption opt = new TestOption("opt" + i); helper.execute(opt); } }
?