搜索
 找回密码
 立即注册

简单一步 , 微信登陆

java线程安全利器——中断信号

作者:赖振军 | 时间:2016-9-27 10:57:10 | 阅读:4108| 只看该作者
在编写java线程过程中,相信大家都有遇到过类似经历。线程还在运行,退出界面时,怎样保证线程能够及时退出。在执行下一次线程,怎样保证线程不被重复执行。两个不同线程同时执行,怎样控制线程先后顺序。
针对这三个问题,我们一个个讨论。
首先,退出一个线程,对于新手,第一反应就是加个变量判断,当变量值符合条件时break或者return跳出循环。 这种方式,初学者常用的,这在功能上存在一个严重bug,当线程循环内部有sleep()函数时, 如果想立即退出线程,做不到,至少得等1个周期的sleep(),才能执行到基于条件判断的变量,才能退出。就是这么一个sleep()时间差值,就有可能导致程序界面退出,线程没能立即退出,如果此时再进入界面,就有可能导致线程重复执行。所以这种变量判断的方式本身就决定了线程不安全。开启一个线程容易,但怎么让线程全身而退,而不增加问题,还是需要多加思考。
这里推荐使用线程自身的中断信号作为线程循环的唯一判断条件,之所以是唯一,是为了不使用变量作为循环判断条件,要不然又回到上面那个问题了。在需要退出线程的地方,直接给线程发一个中断信号,程序处于sleep()状态,收到中断信号也能够立即响应,抛出中断异常,然后执行到下一个while()循环,并及时退出。
线程代码:
private class DeviceThreadextends Thread {
public void run(){
    while (!Thread.interrupted()) { //A
                            if (mBinder == null) {
                                   try {
                                          Thread.sleep(1000);
                                   } catch (InterruptedException e) {
                                          interrupt();//B
                                   }
                     }else{
//Log.d(TAG,”===mBinder isnot null:”+mBinder);
//do something
interrupt();//D
}
}
}
}
//UI退出时,主动给线程发一个中断信号
mDeviceThread.interrupt();//C
A,B,C这三处代码紧密配合,就可以达到线程安全退出的效果。
代码D是演示在某些条件下,如果想让线程退出,可以在线程内部自己给自己发一个中断信号,然后触发while()条件退出。
接着讨论第2个问题,怎样保证线程不被重复执行,这个问题曾经困扰我有一段时间,后来在第1个问题解决之后,这个问题就迎刃而解了。这里,我直接贴上代码。
       private void startDeviceThread(){
              Log.d(TAG, "===startDeviceThread");
    //***START***//
              if(mDeviceThread !=null){                     
          mDeviceThread.interrupt();
                     try{
                     mDeviceThread.join();
                     }catch(InterruptedException e){}
              }
       //***END***//
              mDeviceThread = newDeviceThread();
              mDeviceThread.start();
}
这个函数关键之处就在代码注释START,END之间,在每次开启线程前,先判断mDeviceThread是否为空,不为空,就给它发一个中断信号,并通过join()函数等待之前的线程结束,再创建线程。这样就算连续重复执行startDeviceThread(),也不会重复创建线程。这里再次看到了mDeviceThread.interrupt();它与前面代码A,B配合,可以很稳定地让之前的线程立即退出,保证新线程执行时,之前的线程已经退出。
最后一个问题,控制两个不同线程的执行顺序。其实这个问题在第2个问题中已经有体现,就是join()函数使用。
Thread1t1 = new Thread1();
Thread1 t2 = newThread2();
t1.start();
t1.join(); //通过join函数等待t1结束后,再执行t2。
t2.start();
线程是否安全,很多时候表现在线程是否稳定可控。上面例子中,我们都围绕着一个点, 那就是中断信号。这个特性专为线程设计,可靠性很强,通过它,我们可以很稳定地控制线程。

收藏
收藏0
分享
分享
点赞
点赞0
反对
反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版