接(第二篇) Java 多线程 编程 基础 教程

6、使用线程池ExecuteService

线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就可以强制其他任何新到的请求一直等待,直到获得一个线程来处理位置,从而防止资源不足。

线程池是管理线程的高级技术,通常它提供了如下几个功能

  • 通过对线程的管理,更加合理的调配资源。通常,线程池里维护着一组空闲线程,并向外提供,根据系统繁忙程度动态增加或减少空闲线程的数量。比较高级的还提供了自动检测异常的功能。
  • 通过维护线程池中的既存线程,可以节省创建线程的开销,尤其是对WebServer这类处理频繁,而处理过程又比较快的程序,创建线程的开销不能忽略。

java.util.concurrent提供了互斥、信号量、诸如在并发访问下执行得很好的队列和散列表之类的集合类及几个工作队列实现。该包中的Excutors类是一种有效的、广泛使用的以工作队列为基础的线程池的正确实现。个人无须尝试编写自己的线程池,容易出错。

线程池的创建很简单,只需要使用Excutors.newFixedThreadPool(i)函数即可创建大小为i的线程池,实例属于ExecutorService类型。然后可以调用该类的execute()函数来启动一个线程,输入的参数为线程的变量。

下面是一个简单的例子,使用了2个大小的线程池来处理100个线程。

注意:线程池必须使用shutdown来显示关闭,否则主线程无法退出。

shutdown不会阻塞主线程

package org.test.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Administrator
 *
 *	使用两个线程池来处理100个线程
 * 
 */
public class TestExecuteService {
	public static void main(String[] args) {
		ExecutorService exec = Executors.newFixedThreadPool(2);
		for(int i = 0;i < 100;i++){
			//定义一个内部类
			Runnable run = new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					long time = (long) (Math.random() * 1000);
					System.out.println("休眠"+time);
					try {
						Thread.sleep(time);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			exec.execute(run);
		}
		//必须关闭线程池
		exec.shutdown();
	}
}

在循环过程中,对等待线程池中有空闲的线程,所以主线程会阻塞,为了解决这个问题,一般启动一个线程来做for循环,就是为了避免由于线程池满了造成主线程阻塞。代码如下所示:

package org.test.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Administrator
 *
 *	使用两个线程池来处理100个线程
 */
public class TestExecuteService {
	public static void main(String[] args) {
		new TestExecuteService().testExec(2,100);
		new TestExecuteService().testForExec(2,100);
	}

	/**
	 * 可能会出现线程阻塞
	 * */
	private void testExec(int poolSize,int threadSize) {
		ExecutorService exec = Executors.newFixedThreadPool(poolSize);
		for(int i = 0;i < threadSize;i++){
			//定义一个内部类
			Runnable run = new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					long time = (long) (Math.random() * 1000);
					System.out.println("休眠"+time);
					try {
						Thread.sleep(time);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			exec.execute(run);
		}
		//必须关闭线程池
		exec.shutdown();
	}
	/**
	 * 用一个线程来处理for循环
	 * */
	private void testForExec(final int poolSize,final int threadSize){
		//创建内部类
		class Test extends Thread{

			@Override
			public void run() {
				ExecutorService exec = Executors.newFixedThreadPool(poolSize);
				for (int i = 0; i < threadSize; i++) {
					//定义一个内部类
					Runnable run = new Runnable() {

						@Override
						public void run() {
							// TODO Auto-generated method stub
							long time = (long) (Math.random() * 1000);
							System.out.println("休眠 "+time);
							try {
								Thread.sleep(time);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					};
					exec.execute(run);
				}
				//必须显示关闭线程池
				exec.shutdown();
			}

		}
		new Test().start();
	}
}

在我们编写基于Socket的服务器程序时,通常的做法是,每连接一个客户端都为它创建一个新的线程,客户端离开后再销毁该线程。但是如果频繁的创建多个线程并销毁,对系统资源会造成很大的浪费。然而使用线程池技术就可以大大减少程序的创建和销毁次数,提高服务器的工作效率。

时间: 2024-12-12 12:59:33

接(第二篇) Java 多线程 编程 基础 教程的相关文章

Java多线程编程基础之线程对象

在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念. [线程的并发与并行] 在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent).而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel). 在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储

JAVA读书推荐----《深入分析Java Web技术内幕》--《java多线程编程核心技术》--《大型网站技术架构 核心原理与案例分析》-《Effective Java中文版》

(1)  首先推荐的不是一本书,而是一个博客,也是我们博客园另外一位博友java_my_life. 目前市面上讲解设计模式的书很多,虽然我前面讲了看书是最好的,但是对设计模式感兴趣的朋友们,我推荐的是这个博客.这位博友的设计模式讲得非常非常好,我认为90%的内容都是没有问题且很值得学习的,其讲解设计模式的大体路线是: 1.随便开篇点明该设计模式的定义 2.图文并茂讲解该设计模式中的结构 3.以详细的代码形式写一下该种设计模式的实现 4.补充内容 5.讲解该设计模式的优缺点 对于一个设计模式我们关

《Java多线程编程核心技术》推荐

写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点Java基础,你就可以尝试去阅读它,相信定会收获甚大! 博主之前网上找了很久都没完整pdf电子版的,只有不全的试读版,这里博主提供免费.清晰.完整版供各位猿友下载: http://download.csdn.net/detail/u013142781/9452683 刚刚已经提到,<Java多线程编程核

第12篇-JAVA 多线程

第12篇-JAVA 多线程 每篇一句 :不要只看到艰难,要看艰难后面的胜利 初学心得: 敢于尝试,就等于你已经向成功迈出了第一步 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-04-20| JAVA 多线程 ] 1.进程与线程 1.什么是进程 程序是指令和数据的有序的集合,其本身没有任何运行的含义,是一个静态的概念 进程是一个具有一定独立功能的程序,一个实体 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程 当一个程序运行时,内部可

Java多线程编程详解

线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synch

Java网络编程和NIO详解开篇:Java网络编程基础

Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为我们拥有网络.网络是一个神奇的东西,它改变了你和我的生活方式,改变了整个世界. 然而,网络的无标度和小世界特性使得它又是复杂的,无所不在,无所不能,以致于我们无法区分甚至无法描述. 对于一个码农而言,了解网络的基础知识可能还是从了解定义开始,认识OSI的七层协议模型,深入Socket内部,进而熟练地

Java网络编程基础(六)— 基于TCP的NIO简单聊天系统

在Java网络编程基础(四)中提到了基于Socket的TCP/IP简单聊天系统实现了一个多客户端之间护法消息的简单聊天系统.其服务端采用了多线程来处理多个客户端的消息发送,并转发给目的用户.但是由于它是基于Socket的,因此是阻塞的. 本节我们将通过SocketChannel和ServerSocketChannel来实现同样的功能. 1.客户端输入消息的格式 username:msg    username表示要发送的的用户名,msg为发送内容,以冒号分割 2.实现思路 实现思路与Java网络

Java多线程编程模式实战指南(二):Immutable Object模式--转载

本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-object.转载请注明作者: 黄文海 出处:http://viscent.iteye.com. 多线程共享变量的情况下,为了保证数据一致性,往往需要对这些变量的访问进行加锁.而锁本身又会带来一些问题和开销.Immutable Object模式使得我们可以在不使用锁的情况下,既保证共享变量访问的线程安

Java多线程编程(学习笔记)

一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过多线程的使用,可以编写出非常高效的程序.但如果创建了太多的线程,程序执行的效率反而会降低. 同时上下文的切换开销也很重要,如果创建太多的线程,CPU花费在上下文的切换时间将对于执行程序的时间. 二.Java多线程编程 概念 在学习多线程时,我们应该首先明白另外一个概念. 进程:是计算机中的程序关于某