Android线程异常问题:如何让定时任务稳定无干扰运行
问题描述
需要在指定时间后执行任务且不关联UI线程,编写了Thread代码,要求doWork1()每隔10秒执行一次,imgUpload()不干扰该线程。但实际运行时,imgUpload()执行期间doWork1()暂停,计时正常,上传完成后doWork1()会在1-2秒内连续执行。尝试用Timer实现doWork1()定时,结果无变化。从嵌入式C转Android开发,求解决方法。
相关代码
计时线程实现
private int cntUpdate; //count time to update work1 private int cntUpload; //count time to upload to server private int cntlosing; //count time losing gps private void creatThread(){ Thread myThread = new Thread(){ @Override public void run(){ try{ while (!isInterrupted()){ Thread.sleep(1000);//1s cntUpdate ++; if(cntUpdate >= 10){ //10s doWork1(); //AsyncTask cntUpdate = 0; } cntUpload ++; if(cntUpload > 100){//100s imgUpload(); //AsyncTask cntUpload = 0; } if(isGpsLosing()){ //checking every sec cntlosing ++; if(cntlosing > 500){ doSomething(); cntlosing = 0; } } } }catch (InterruptedException e) { Log.d(TAG, "Interruped : " + e); } } }; myThread.start(); }
AsyncTask任务实现
private void doWork1(){ AsyncWork1 asyncWork1 = new AsyncWork1(); asyncWork1.execute(); } public class AsyncWork1 extends AsyncTask<Void, Void, Void>{ @Override protected Void doInBackground(Void... voids) { databaseWork(); // get data from table, some calculates... return null; } } private void imgUpload(){ UpLoadImg upload = new UpLoadImg(); upload.execute(); } public class UpLoadImg extends AsyncTask<Void, Void, Void>{ @Override protected Void doInBackground(Void... voids) { sendImgtoServer(); // return null; } }
Timer尝试实现
private void useTimerWork1(){ new Timer().scheduleAtFixedRate(new TimerTask() { @Override public void run(){ doWork1(); } }, 0, 10*1000); //every 10s }
解决方法
核心原因
Android 3.0及以上版本中,AsyncTask默认使用串行线程池,所有doInBackground任务会按顺序排队执行。当imgUpload()的任务在执行时,doWork1()的AsyncTask会被阻塞在队列中,直到上传完成才会执行,这就导致了"暂停后连续执行"的现象。Timer方案无效的原因是,它只是定时触发doWork1(),但任务本身还是依赖串行的AsyncTask池,根源问题未解决。
具体解决方案
1. 让AsyncTask并行执行
将execute()替换为executeOnExecutor(),指定使用系统提供的并行线程池,这样多个AsyncTask可以同时运行:
private void doWork1(){ AsyncWork1 asyncWork1 = new AsyncWork1(); asyncWork1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } private void imgUpload(){ UpLoadImg upload = new UpLoadImg(); upload.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
2. 改用现代多线程方案(推荐)
AsyncTask已在API 30+被标记为废弃,推荐使用更灵活的线程管理方案:
- ExecutorService线程池:手动创建线程池,独立管理任务线程:
// 初始化线程池(根据需求调整核心线程数) private ExecutorService taskExecutor = Executors.newFixedThreadPool(3); private void doWork1(){ taskExecutor.submit(() -> databaseWork()); } private void imgUpload(){ taskExecutor.submit(() -> sendImgtoServer()); } - 协程(Kotlin)/RxJava:如果项目支持,协程是Android异步任务的首选方案,语法更简洁且易于管理生命周期。
- WorkManager:如果是周期性任务,
WorkManager可以保证任务在合适的时机执行,即使应用退出或设备重启。
3. 调整原计时线程逻辑
保留原计时线程,但直接在新线程中执行任务,避免依赖AsyncTask:
private void creatThread(){ Thread myThread = new Thread(){ @Override public void run(){ try{ while (!isInterrupted()){ Thread.sleep(1000);//1s cntUpdate ++; if(cntUpdate >= 10){ //10s // 直接开启新线程执行数据库任务,不阻塞计时线程 new Thread(() -> databaseWork()).start(); cntUpdate = 0; } cntUpload ++; if(cntUpload > 100){//100s // 开启新线程执行上传任务 new Thread(() -> sendImgtoServer()).start(); cntUpload = 0; } if(isGpsLosing()){ //checking every sec cntlosing ++; if(cntlosing > 500){ doSomething(); cntlosing = 0; } } } }catch (InterruptedException e) { Log.d(TAG, "Interruped : " + e); } } }; myThread.start(); }
内容的提问来源于stack exchange,提问作者Jamebes
相关产品推荐
相关产品推荐

