在 ThreadPoolExecutor类中有三个空的方法,可以看到这三个方法都是protected权限的
protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
protected void terminated() { }
父类的protected成员是包内可见的,并且对子类可见;
若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。
那么我们创建的线程池实例就不可以直接访问 ThreadPoolExecutor的这三个方法,但是可以通过匿名内部类重写这三个方法来提供方法的可见性。
new ThreadPoolExecutor()其实是子类的对象,就是匿名类的对象,这个类其实继承了ThreadPoolExecutor,pool是父类的引用。子类重写父类的方法,是多态的体现
多态中,父类的引用只能使用子类已经覆盖的方法,不能使用子类特有的方法,在这个例子中,要访问的不不是子类特有的方法,而是父类引用不可见的方法(protected的可见性的第二点)
package xidian.lili.reentrantlock;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import xidian.lili.reentrantlock.ThreadFactoryDemo.MyTask;
public class ExtThreadPool {
public static class MyTask implements Runnable{
public String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println("正在执行:Thread ID"+Thread.currentThread().getId()+" is execute "+this.name);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService pool=new ThreadPoolExecutor(5,5,0L,TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(10)){
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println(t.getId()+"准备执行 "+((MyTask)r).name);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println(((MyTask)r).name+" 执行完毕");
}
@Override
protected void terminated() {
System.out.println("线程池退出");
}
};
for(int i=0;i<5;i++){
MyTask task=new MyTask("task"+i);
pool.execute(task);
Thread.sleep(10);
}
pool.shutdown();
}
}
那么通过重写这三个方法我们可以对线程池的运行状态进行跟踪,输出一些有用的调试信息,最后我们使用shutdown方法退出线程池。
(1)shutdown()关闭线程池,但是不会强制退出,而是等到已提交的任务全部执行完,但是一旦调用shutdown,就不会接受新提交的任务,会抛出RejectedExecutionException异常
(2) public List
(3)上一篇中我们重写了ThreadFactory将线程池的线程设置为守护线程,程序执行完(主线程执行完),也会强制退出线程池
(1)使用标志位,while(true)
(2)Thread.interrupt()发出中断信号中断目标线程,实际上也只是设置中断标志位为true,对中断正确的理解是:并不真正中断正在运行的线程,而只是发出中断请求,由线程在下一个合适的时刻中断自己。中断是取消线程最合理的方式。
会检查中断状态并响应的阻塞库包括:
1、Thread.sleep()
2、Object.wait()
3、BlockingQueue.put()/take()
4、Thread.join()
5、lock.lockinterruptibly() (lock.lock不支持中断)
6、Condition.await() (Condition.awaitUninterruptibly()不支持中断)
7、SemapDemo.acquire() (SemapDemo.acquireUninterruptibly()不支持中断 )
8、CyclicBarrier.await()
9、CountDownLatch.await()
10、LockSupport.park()
如果代码中不会调用可中断的阻塞方法,那么也可以通过在任务代码中轮询当前线程的中断状态来响应中断,只是这样中断响应性依赖于任务执行的时间。Thread.currentThread().isInterrupted()方法检查中断标志
(3)从Future的实现子类FutureTask针对cancel()方法的实现中可以看出,cancel()方法取消线程的方法是调用interrupt()方法尝试中断线程。
有经验公式
Nthread=Ncpu*Ucpu*(1+W/C)
W/C:等待时间与计算时间的比值
Ncpu:CPU数量
Ucpu:目标cpu的使用率
Java中下面方法获取CPU数目
int Ncpus=Runtime.getRuntime().availableProcessors();
System.out.println(Ncpus);