代码之家  ›  专栏  ›  技术社区  ›  Civyshk

java/android线程中长的、不可交互的方法的替代方法

  •  1
  • Civyshk  · 技术社区  · 8 年前

    在Android应用程序的UI线程中,我需要运行一个可能需要纳秒或永远才能完成的方法。我想我不能确切地确定什么时候需要永远,所以我在一个单独的线程中通过一个池来运行它。

    myPool = Executors.newCachedThreadPool(new ThreadFactory(){
        //override newThread(Runnable r)...
    });
    
    Future<Result> futureResult = myPool.submit(new Callable<Result>(){
        @Override public Result call(){
            return dangerousMethod();
        }
    });
    

    try{
        Result result = futureResult.get(1, TimeUnit.SECONDS);
        //Use result here
    }catch(TimeoutException e) {//Other Exceptions are ommited
        futureResult.cancel(true);
        Log.d("DEMO", "Method takes too long. Skip");
    }
    

    futureResult.cancel(true) ,但 dangerousMethod() 不会对中断做出响应,因此线程将继续运行,直到最终完成其任务。

    ThreadPoolExecutor 并获得私人 Thread ThreadPoolExecutor$Worker.thread )强制(不良行为TM)执行以下任一操作: stop() (不工作,因为 UnsupportedOperationException )或者 stop0() (也不工作,因为 NoSuchMethodException ). 更多详细信息:

    class MyPool extends ThreadPoolExecutor{
        //constructor, reflection code to get the Threads, etc
    
        void cancelThread(Thread thread){
            try {
                thread.stop();
            }catch(SecurityException | UnsupportedOperationException e) {
                try {
                    Method stopMethod = Thread.class.getDeclaredMethod("stop0", Object.class);
                    stopMethod.setAccessible(true);
                    stopMethod.invoke(thread, new ThreadDeath());
                }catch(NoSuchMethodException | 
                       InvocationTargetException | 
                       IllegalAccessException x)
                {
                    Log.d("MyPool", "Can't stop thread", x);
                }
            }
        }
    }
    

    危险的方法实际上是这样的:

    BigDecimal n1 = new BigDecimal("1E1000000");
    BigDecimal n2 = new BigDecimal("1");
    BigDecimal result = n1.add(n2);//Takes too long
    

    BigDecimal n3 = new BigDecimal("1E999999");
    BigDecimal result = n1.add(n3);
    

    1 回复  |  直到 8 年前
        1
  •  0
  •   Tomasz Stanczak    8 年前

    在Android中,你似乎无法强制杀死Java线程——在Oracle Java中,它实际上仍然有效。原因是在Oracle Java中 stop() 电话 stop1() ,而在Android上,它调用 stop(new ThreadDeath()) UnsupportedOperationException .

    如果长时间运行的后台线程在完成后尝试执行操作,您可以设置一个标志,告诉他闭嘴。只要你不需要它的结果,你就是好的。