Java中线程池的使用

一、线程池的作用

线程池的作用就是限制系统中执行线程的数量
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;
少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,
其他线程排队等候。一个任务执行完毕,再从队列中取最前面的任务开始执行。
若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,
如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

二、线程池的优点

  • 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  • 可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开得越多,消耗的内存也就越大,最后死机。)

三、Executors

Java 里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而是一个执行线程的工具。真正的线程池接口是ExecutorService。ThreadPoolExecutor 是 Executors 类的底层实现。

线程池创建线程大致可以分为三种:
  • 固定大小连接池
    使用多线程需要实现Runnable 接口对象,这里直接继承Thread 。
    因为Thread也实现了 Runnable 接口
	public class MyThread extends Thread
	{
    	@Override
    	public void run(){
        	System.out.println(currentThread().getName()+" is Running ...");
    	}
	}

	public static void main(String args)
	{
		//创建一个可重用且固定线程数的线程池
		int pool_num = 2 ;
		//固定大小连接池 :不管 execute 执行几次,线程池始终都会使用 pool_num  个线程来处理
		ExecutorService pool = Executors.newFixedThreadPool(pool_num);
		
		// pool_num 等于2 ,我们启动4个线程来测试
		Thread t1 = new MyThread();
		Thread t2 = new MyThread();
		Thread t3 = new MyThread();
		Thread t4 = new MyThread();

		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		
		//关闭线程池
		pool.shutdown();
	}
	

运行结果

pool-1-thread-1 is Running ...
pool-1-thread-1 is Running ...
pool-1-thread-1 is Running ...
pool-1-thread-2 is Running ...

从上面的运行来看,我们 Thread 类都是在线程池中运行的,线程池在执行 execute 方法来执行 Thread 类
中的 run 方法。不管 execute 执行几次,线程池始终都会使用 2 个线程来处理。不会再去创建出其他线程来处理run 方法执行。这就是固定大小线程池。

  • 单任务连接池
	ExecutorService pool = Executors.newSingleThreadExecutor();
	Thread t1 = new MyThread();
    Thread t2 = new MyThread();
    pool.execute(t1);
    pool.execute(t2);

    pool.shutdown();

运行结果

pool-1-thread-1 is Running ...
pool-1-thread-1 is Running ...

不管 execute 执行几次,线程池始终都会使用单个线程来处理。

  • 可变连接池
	    ExecutorService pool = Executors.newCachedThreadPool();
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();
        Thread t4 = new MyThread();

        //将线程放入线程池中执行
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);

        //关闭线程池
        pool.shutdown();

运行结果

pool-1-thread-1 is Running ...
pool-1-thread-2 is Running ...
pool-1-thread-3 is Running ...
pool-1-thread-4 is Running ...

这里 execute 执行多次,线程池就会创建出多个线程来处理 Thread 类中 run 方法。
我们看到连接池会根据执行的情况,在程序运行时创建多个线程来处理,这里就是可变连接池的特点。

四、ExecutorService 执行器服务

java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务。
因此一个 ExecutorService 很类似于一个线程池。实际上,存在于 java.util.concurrent 包里的 ExecutorService 实现就是一个线程池实现。

//线程工厂类创建出线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//执行一个线程任务
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
//线程池关闭
executorService.shutdown();

上面代码首先使用 newFixedThreadPool() 工厂方法创建一个 ExecutorService。
这里创建了一个固定大小为10的线程执行任务的线程池。然后,将一个 Runnable
接口的匿名实现类传递给 execute() 方法。
这将导致 ExecutorService 中的某个线程执行该 Runnable。
这里可以看成一个任务分派,示例代码中的任务分派我们可以理解为:

  • 一个线程将一个任务委派给一个 ExecutorService 去异步执行。
  • 一旦该线程将任务委派给 ExecutorService,该线程将继续它自己的执行,独立于该任务的执行。

你可能感兴趣的:(JAVA,线程池,Executor)