Java并发库入门---线程连接池

Java的并发编程中较常用的是java.util.concurrent这个包,下面也是围绕这个包说明。该包主要有以下一些组件:

  • 执行程序(线程池)
  • 并发队列
  • 同步器
  • 并发Collocation

什么是线程池?

线程池就是限制系统中执行线程的数量,线程管理是一个棘手的问题,少了浪费了系统的资源,多了会造成系统的拥挤导致效率不高,而通过线程池,我们可以根据系统的运行情况,自动或者手动的设置线程的数量,达到最佳的运行效果。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列中取最前面的任务开始执行。如果队列中没有等待任务,线程池则一直处于等待状态。当一个新任务需要运行时,线程池如果有等待的工作线程,就可以开始运行,否则处于等待。

为什么要用线程池?

  • 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用。
  • 可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,把服务器弄崩。

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

线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多的线程,池中线程调度由池管理器来处理,当有线程任务时,从池中取一个,执行完后线程对象归池,这样可以避免反复创建线程带来的性能开销。

java5的并发库中,线程池大概分为下面四种:

    //创建固定大小的线程池
	ExecutorService fpool = Executors.newFixedThreadPool(3);
	//创建缓存大小的线程池
	ExecutorService cpool = Executors.newCachedThreadPool();
	//创建单任务线程池
	ExecutorService spool = Executors.newSingleThreadExecutor();
	//创建延迟线程池
	ScheduledExecutorService scpool = Executors.newScheduledThreadPool(2);

下面通过简单的例子分别说明

  • 固定大小的连接池

      package ThreadPool;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      
      public class ThreadPoolDemo {
      	public static void main(String[] args) {
      		Thread t1 = new MyThread();
      		Thread t2 = new MyThread();
      		Thread t3 = new MyThread();
      		Thread t4 = new MyThread();
      		Thread t5 = new MyThread();
      		//创建可重用固定线程数的线程池
      		ExecutorService fpool = Executors.newFixedThreadPool(3);
      		//将线程放入池中执行
      		fpool.execute(t1);
      		fpool.execute(t2);
      		fpool.execute(t3);
      		fpool.execute(t4);
      		fpool.execute(t5);
      		//关闭线程池
      		fpool.shutdown();
      	}
      }
      class MyThread extends Thread{
      	@Override
      	public void run() {
      		// TODO Auto-generated method stub
      		System.out.println(Thread.currentThread().getName()+"正在执行...");
      	}
      }
    

运行结果:

pool-1-thread-2正在执行...
pool-1-thread-3正在执行...
pool-1-thread-1正在执行...
pool-1-thread-3正在执行...
pool-1-thread-2正在执行...

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

  • 可变连接池

我们将上面
//创建可重用固定线程数的线程池
ExecutorService cpool = Executors.newFixedThreadPool(3);
改为

//无界队列方式的线程池
ExecutorService spool = Executors.newCachedThreadPool();

运行结果:

pool-1-thread-1正在执行...
pool-1-thread-4正在执行...
pool-1-thread-2正在执行...
pool-1-thread-3正在执行...
pool-1-thread-5正在执行...

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

  • 单任务连接池
    我们将上面
    //无界队列方式的线程池
    ExecutorService spool = Executors.newCachedThreadPool();

    改为

      //创建一个使用单个worker线程的executor
      ExecutorService spool = Executors.newSingleThreadExecutor();
    

运行结果:

pool-1-thread-1正在执行...
pool-1-thread-1正在执行...
pool-1-thread-1正在执行...
pool-1-thread-1正在执行...
pool-1-thread-1正在执行...

运行结果可以看出,单任务线程池在执行execute方法来执行Threadrun方法时,不管execute执行几次,线程池始终都会使用单个线程处理。

  • 延迟线程池

    package ThreadPool;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.ScheduledExecutorService;
      import java.util.concurrent.ScheduledThreadPoolExecutor;
      import java.util.concurrent.TimeUnit;
      
      public class ThreadPoolDemo {
      	public static void main(String[] args) {
      		Thread t1 = new MyThread();
      		Thread t2 = new MyThread();
      		Thread t3 = new MyThread();
      		Thread t4 = new MyThread();
      		Thread t5 = new MyThread();
      		//创建线程池,它可以安排在给定延迟后运行命令或者定期的执行
      		ScheduledExecutorService scpool = Executors.newScheduledThreadPool(2);
      		//将线程放入池中执行
      		scpool.execute(t1);
      		scpool.execute(t2);
      		scpool.execute(t3);
      		//使用定时执行风格的方法
      		scpool.schedule(t4, 10, TimeUnit.MILLISECONDS);
      		scpool.schedule(t5, 10, TimeUnit.MILLISECONDS);
      		//关闭线程池
      		scpool.shutdown();
      	}
      }
      class MyThread extends Thread{
      	@Override
      	public void run() {
      		// TODO Auto-generated method stub
      		System.out.println(Thread.currentThread().getName()+"正在执行...");
      	}
      }
    

运行结果:

pool-1-thread-2正在执行...
pool-1-thread-1正在执行...
pool-1-thread-2正在执行...
pool-1-thread-1正在执行...
pool-1-thread-2正在执行...

本篇博文为自己学习时记录,难免有错误的地方,欢迎大家讨论指出。

你可能感兴趣的:(并发与多线程)