Java多线程9-线程管理

314 阅读6分钟
原文链接: mp.weixin.qq.com

 一、线程组

        线程与线程组的关系,类似于文件与文件夹之间的关系;一个线程组可以包含多个线程以及其他线程组,Thread类有几个构造函数允许我们在创建线程的时候指定线程所属的线程组,如果没有指定,这个线程则属于其父线程所属线程组

 

        由于Java虚拟机在创建main线程时,会为其指定一个线程组;因此Java平台中的任何一个线程都有一个线程组与之关联,这个线程组可以通过Thread.getThreadGroup()调用来获取

 

因为ThreadGroup设计缺陷,在实际应用中放弃了对其使用;其取代方案有

a、将线程存入一个数组或集合对象中,但得注意内存泄露

b、使用线程名称的命名规则来实现

 

 

二、可靠性:线程的未捕获异常与监控

如果线程的run方法抛出未被捕获的异常,随着run方法的退出,相应的线程也提前终止;对于线程的这种异常终止,JDK 1.5中引入了UncaughtExceptionHandler接口,在Thread内部定义的方法:void uncaughtException(Thread t, Throwable e) ;t:异常终止的线程本身,导致线程终止的异常;

 

怎么设置捕获异常的线程呢?

我们在启动thread前通过调用thread.setUncaughtExceptionHandler(new  UncaughtExceptionHander())来为thread关联;当thread抛出未被捕获的异常后run()返回,接着在thread终止前调用uncaughtException方法

demo:

public class ThreadMonitorDemo{    volatileboolean inited = false;    static int threadIndex = 0;    final static LoggerLOGGER = Logger.getAnonymousLogger();    final BlockingQueue<String> channel = new ArrayBlockingQueue<String>( 100);    public static void main (String[] args) throwsInterruptedException {        ThreadMonitorDemothreadMonitorDemo = new ThreadMonitorDemo();        threadMonitorDemo.init();        for ( int i =0; i < 100; i++) {            threadMonitorDemo.service( "test- " + i);        }        Thread.sleep(2000) ;        System.exit(0 );    }    privatesynchronized void init(){        if(inited) {            return;        }        System.out .println("init----") ;        WorkerThreadworkerThread = new WorkerThread();        workerThread.setName("Worker0-" + threadIndex );        // 为thread关联一个 uncaughtExceptionHandler        workerThread.setUncaughtExceptionHandler( new ThreadMonitor());        workerThread.start();         inited = true;    }    privatevoid service(Stringmessage) throws InterruptedException{        channel .put(message);    }    privateclass WorkerThread extends Thread {        @Override        publicvoid run (){            System.out .println("dosomething important..." );            Stringmsg;            try {                for (;; ){                    msg = channel .take();                    process(msg);                }            }catch (InterruptedException e) {            }        }        privatevoid process(Stringmessage) throws InterruptedException{            System.out .println(message);            if ((int ) (Math.random() * 100 ) < 2) {                thrownew RuntimeException( "test" ) ;            }            Thread.sleep( 100 ) ;        }    }    privateclass ThreadMonitor implements Thread.UncaughtExceptionHandler {        @Override        publicvoid uncaughtException (Threadt , Throwable e) {            System.out .println( "currentthread is " + Thread.currentThread() + "it is still alive:%s" + t.isAlive()) ;            // 将线程异常终止的相关信息记录到日志中             StringthreadInfo = t.getName() ;            LOGGER .log(Level.SEVERE , threadInfo + "terminated: " , e) ;            // 创建并启动替代线程             LOGGER .info( "About to restart " + threadInfo) ;            // 重置线程启动标志             inited = false;            init() ;        }    }}

 

如果一个线程没有关联的UncaughtExceptionHandler实例,那么该线程异常终止前其所属线程组的uncaughtException方法会被调用,线程组的uncaughtException方法会调用其父线程组的方法并传递同样的两个参数

 三、有组织有纪律:线程工厂

ThreadFactory创建线程的工厂方法:

public Thread newThread(Runnable r)

 

四、线程的暂挂与恢复

Thread.suspend()、Thread.resume()这两个都是已废弃的方法,分别是暂挂(与暂停含义相同)与恢复(与唤醒含义相同);废弃后的替代方案:

设置一个线程暂挂标志,线程每次执行比较耗时的操作前都先检查一下这个标志,如果该标志应该暂挂,则执行Object.wait()/Condition.await()暂停;直到其他线程重置设置该暂挂标志并将其唤醒。

public class PauseControl extends ReentrantLock {    private static final long serialVersionUID = 21321213213131L;    //现在暂挂标志    private volatile boolean suspended = false;    private final Condition condSuspended = newCondition();    /**     * 暂停线程相当于 Thread.suspend()     */    public void requestPause() {        suspended = true;    }    /**     * 恢复线程相当于 Thread.resume()     */    public void proceed() {       lock();       try {           suspended = false;           condSuspended.signalAll();       } finally {           unlock();       }    }    /**     * 当前线程仅在线程暂挂标志不为true的情况下才执行指定的目标动作     * @param targetAction     * @throws InterruptedException     */    public void pauseIfNeccessary(Runnable targetAction) throws InterruptedException {        lock();        try {            while (suspended) {                condSuspended.await();            }            targetAction.run();        } finally {            unlock();        }    }}