首页 > 代码库 > Java线程详解(二)
Java线程详解(二)
Java线程:新特征-线程池
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建连接池的静态方法,是必须掌握的。
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
一、 固定大小的线程池 newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
// 创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
pool.execute(new Runnable() {
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " " + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
// 关闭线程池
pool.shutdown();
}
}
执行结果:
pool-1-thread-3 2
pool-1-thread-2 1
pool-1-thread-1 0
pool-1-thread-1 3
pool-1-thread-2 5
pool-1-thread-3 4
pool-1-thread-2 7
pool-1-thread-1 6
pool-1-thread-3 8
pool-1-thread-1 9
因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
二、单任务线程池 newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。在上例的基础上改一行创建pool对象的代码为:
//创建一个使用单个 worker线程的 Executor,以无界队列方式来运行该线程。
ExecutorService pool = Executors.newSingleThreadExecutor();
输出结果为:
pool-1-thread-1 0
pool-1-thread-1 1
pool-1-thread-1 2
pool-1-thread-1 3
pool-1-thread-1 4
pool-1-thread-1 5
pool-1-thread-1 6
pool-1-thread-1 7
pool-1-thread-1 8
pool-1-thread-1 9
结果依次输出,相当于顺序执行各个任务。
对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。
一旦池中有线程完毕,则排队等待的某个线程会入池执行。
三、可变尺寸的线程池
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。与上面的类似,只是改动下pool的创建方式:
// 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
// 创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
final int index = i;
pool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + " " + index);
}
});
}
// 关闭线程池
pool.shutdown();
}
}
pool-1-thread-1 0
pool-1-thread-6 5
pool-1-thread-5 4
pool-1-thread-10 9
pool-1-thread-4 3
pool-1-thread-3 2
pool-1-thread-2 1
pool-1-thread-9 8
pool-1-thread-8 7
pool-1-thread-7 6
四、延迟连接池
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
}
}
public class TestThread {
public static void main(String[] args) {
// 创建一个可重用固定线程数的线程池
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
// 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
// 将线程放入池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
// 使用延迟执行风格的方法
pool.schedule(t4, 3, TimeUnit.SECONDS);
pool.schedule(t5, 3, TimeUnit.SECONDS);
// 关闭线程池
pool.shutdown();
}
}
执行结果:
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
Process finished with exit code 0
表示t4,t5延迟3秒执行。
定期执行示例代码如下:
class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在执行。。。"); } } public class TestThread { public static void main(String[] args) { // 创建一个可重用固定线程数的线程池 ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); // 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); // 将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); // 使用延迟执行风格的方法 pool.scheduleAtFixedRate(t4, 1, 3, TimeUnit.SECONDS); pool.scheduleAtFixedRate(t5, 1, 3, TimeUnit.SECONDS); } }
执行结果:
pool-1-thread-2正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-2正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-2正在执行。。。 pool-1-thread-1正在执行。。。
表示t4,t5延迟1秒后每3秒执行一次。
五、单任务延迟连接池
在四代码基础上,做改动
//创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
Process finished with exit code 0
六、自定义线程池
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Java线程:线程池-自定义线程池
*/
publicclass Test {
public static void main(String[] args) {
//创建等待队列
BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);
//创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue);
//创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
Thread t6 = new MyThread();
Thread t7 = new MyThread();
//将线程放入池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
//关闭线程池
pool.shutdown();
}
}
class MyThread extends Thread {
@Override
publicvoid run() {
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
Process finished with exit code 0
创建自定义线程池的构造方法很多,本例中参数的含义如下:
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
用给定的初始参数和默认的线程工厂及处理程序创建新的ThreadPoolExecutor。使用Executors工厂方法之一比使用此通用构造方法方便得多。
参数:
corePoolSize -池中所保存的线程数,包括空闲线程。
maximumPoolSize -池中允许的最大线程数。
keepAliveTime -当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime参数的时间单位。
workQueue -执行前用于保持任务的队列。此队列仅保持由execute方法提交的Runnable任务。
抛出:
IllegalArgumentException -如果 corePoolSize或 keepAliveTime小于零,或者 maximumPoolSize小于或等于零,或者 corePoolSize大于 maximumPoolSize。
NullPointerException -如果workQueue为 null
自定义连接池稍微麻烦些,不过通过创建的ThreadPoolExecutor线程池对象,可以获取到当前线程池的尺寸、正在执行任务的线程数、工作队列等等。
有关Java5线程池的内容到此就没有了,更多的内容还需要研读API来获取.
本文出自 “ciyo技术分享” 博客,请务必保留此出处http://ciyorecord.blog.51cto.com/6010867/1939535
Java线程详解(二)