线程处理的基本问题

JVM为线程抛出非捕获异常时,有三种可能的处理器:首先、寻找抛出这个异常线程的非捕获异常处理器;若不存在,则查找这个线程所在的线程组的非捕获异常处理器;若还不存在,JVM将寻找默认的非捕获异常处理器
1)Java的run()方法不支持throws语句,默认行为是在控制台下进行打印堆栈记录并退出程序。
若要获取异常,需要实现UncaughtExceptionHandler接口,并实现该接口的uncaughtException()方法,在线程启动前,加入thread.setUncaughtExceptionHandler(new ExceptionHandler());来捕获异常。
还可通过静态方法setDefaultUncaughtExceptionHandler(),该方法在应用程序中为所有的线程对象创建了一个异常处理器。
2)处理非捕获异常
// Check the interruption
  if (Thread.interrupted()) {
   throw new InterruptedException();
  }
3)Java提供ThreadGroup类表示一组线程。线程组可以包含线程对象,也可以包含其他线程组对象,它是一个树形结构。
    java.lang.Thread.Thread(ThreadGroup group, Runnable target)
如:创建10个线程,模拟一个 查询,当其中一个线程查询成功时,我们终端其余9个线程。
4)线程组中不可控异常的处理
继承线程组ThreadGroup,并覆盖uncaughtException()方法。

interrupt、interrupted 、isInterrupted 区别:
在java的线程Thread类中有三个方法,比较容易混淆,在这里解释一下
(1)interrupt:置线程的中断状态 ,不会中断正在执行的线程,只是将线程的标志位设置成true。
(2)isInterrupt:线程是否中断
(3)interrupted:返回线程的上次的中断状态,并清除中断状态

interrupt()是用来设置中断状态的。返回true说明中断状态被设置了而不是被清除了。我们调用sleep、wait等此类可中断(throw InterruptedException)方法时,一旦方法抛出InterruptedException,当前调用该方法的线程的中断状态就会被jvm自动清除了,就是说我们调用该线程的isInterrupted 方法时是返回false。如果你想保持中断状态,可以再次调用interrupt方法设置中断状态。这样做的原因是,java的中断并不是真正的中断线程,而只设置标志位(中断位)来通知用户。如果你捕获到中断异常,说明当前线程已经被中断,不需要继续保持中断位。
interrupted是静态方法,返回的是当前线程的中断状态。例如,如果当前线程被中断(没有抛出中断异常,否则中断状态就会被清除),你调用interrupted方法,第一次会返回true。然后,当前线程的中断状态被方法内部清除了。第二次调用时就会返回false。如果你刚开始一直调用isInterrupted,则会一直返回true,除非中间线程的中断状态被其他操作清除了。
import java.util.Timer;  
import java.util.TimerTask;  
 
class CanStop extends Thread {  
 
    private int counter = 0;  
 
    public void run() {  
        boolean done = false;  
        try{  
            Thread.sleep(100);//设置成100比主线程中的102要小  
        }catch(InterruptedException ie){  
            ie.printStackTrace();  
            //return;假如要使用interrupt来终止线程则在捕获的InterruptedException中return
        }  
        while (counter < 100 &&!done) {  
            System.out.println(counter++);  
            //在主线程中调用stoppable.interrupt()之前为false,假如之后没有调用Thread.interrupted()则一直为true,  
            //否则为第一次为true,调用Thread.interrupted之后为false  
            System.out.println("in thread stoppable.isInterrupted() "+isInterrupted());  
             
            System.out.println("stoppable.isInterrupted() "+Thread.interrupted());在主线程中调用stoppable.interrupt()之前为false,之后只有第一个会显示为true,之后全为false  
             
            //调用Thread.interrupted()一次会清除线程的中断标志位,因此以后都为false  
            if(Thread.interrupted()==true){  
                try{  
                    //Thread.interrupted()会清除中断标志位,显然这里面只会调用一次  
                    System.out.println("in thread after Thread.interrupted() "+isInterrupted());  
                    sleep(10000);  
                }catch(InterruptedException ie){  
                    ie.printStackTrace();  
                     
                }  
            }  
        }  
    }  
}  
 
public class CheckInterrupt {  
    public static void main(String[] args) {  
        final CanStop stoppable = new CanStop();  
        stoppable.start();  
        new Timer(true).schedule(new TimerTask() {  
            public void run() {  
                System.out.println("Requesting Interrupt");  
                stoppable.interrupt();//不会中断正在执行的线程,原因是因为interrupt()方法只设置中断状态标志位为true  
                System.out.println("in timer stoppable.isInterrupted() "+stoppable.isInterrupted());  
                System.out.println("in timer2 stoppable.isInterrupted() "+stoppable.isInterrupted());
            }  
        }, 102); // run() after 500 milliseconds  
    }  
}  
对于InterruptedException的处理,可以有两种情况:
(1)外层代码可以处理这个异常,直接抛出这个异常即可
(2)如果不能抛出这个异常,比如在run()方法内,因为在得到这个异常的同时,线程的中断状态已经被清除了,需要保留线程的中断状态,则需要调用Thread.currentThread().interrupt()

5)避免过多的同步,永远不要在循环外面调用wait 。Object.wait方法的作用是使一个线程等待某个条件。它一定是在一个同步区域中被调用,而且该同步区域锁住了被调用的对象。下面是wait方法的标准模式: 
synchronized(obj){  
      while(<condition does not hold>)  
            obj.wait();  
      ...//perform action appropriate to condition  
}  
总是使用wait循环模式来调用wait方法。而不是if来调用。永远不要在循环的外面调用wait。


1)Java并发API提供了一个干净的机制,即线程局部变量(Thread-Local Variable),可声明一个ThreadLocal<T>对象,在这个对象的initialValue()方法中隐式实现。如
private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() {
  protected Date initialValue(){
   return new Date();
  }
 };
通过startDate.get()方法获取。
2)使用工厂类创建线程----实现ThreadFactory接口,并实现public Thread newThread(Runnable r) 接口
3)在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。
4)yield()方法将通知JVM这个线程对象可以释放CPU了,JVM并不保证遵循这个要求,通常来说,yield()方法只做调试使用。
当一个线程对象的join()方法被调用时,调用它的线程被挂起,直到这个线程对象完成它的任务。
5)守护线程 setDaemon(true)
6)InheritableThreadLocal和ThreadLocal
         //使用ThreadLocal,父子线程之间,不共享Value
         final ThreadLocal<String> tl = new ThreadLocal<String>();
           tl.set("ThreadLocal-VAL");
           System.out.println("Main-1:" + tl.get());
           new Thread() {
             public void run() {
                   System.out.println("Child-1:" + tl.get());
             };
         }.start();
 
           //使用InheritableThreadLocal,父线程Value可让子线程共享
          final ThreadLocal<String> itl = new InheritableThreadLocal<String>();
           itl.set("InheritableThreadLocal-VAL");
          System.out.println("Main-2:" + itl.get());
           new Thread() {
               public void run() {
                 System.out.println("Child-2:" + itl.get());
               };
          }.start();
结果:
Main-1:ThreadLocal-VAL
Main-2:InheritableThreadLocal-VAL
Child-1:null
Child-2:InheritableThreadLocal-VAL




常用方法:
TimeUnit.SECONDS.sleep(2); //效果等同于Thread.sleep(2000);
Math.rint(1.2)                        //四舍五入取整的double型
threadGroup.list();                //用于打印调试信息

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值