Java 多线程应用

java项目中多线程的应用方式相对简单,这都归功于大师Doug Lea的卓越贡献。本文从以下几个方面说说java的多线程应用。

※ 进程和线程
※ 线程池
※ 多线程应用
※ 总结


一、进程和线程
“进程”和“线程”是计算机世界中两个重要的概念。在操作系统中扮演着不同的角色,其特点和用途各有不同。先来看看官方的定义,(摘自百度)——进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配基本单位,是操作系统结构的基础。线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。抛开从范围方面的定义,我们可以这样理解:进程——一个正在运行的应用程序;线程——一个正在运行的应用程序中的一个子任务。程序是静态的、是一些列指令和数据的有序集合,程序的执行过程就是进程的生命周期;进程又像一个容器,其中包含众多线程,程序中的具体任务都是由这些线程来实现。文字描述概念总是抽象的,咱们看图说话:

图中的各项指标能直观反映上述“程序”、“进程”、“线程”之间的关系,进程名Eclipse就是我使用的开发工具。划重点——线程的创建是耗资源的,重复的创建线程会加剧系统可用资源的枯竭,以此引出下面的知识点“线程池”。

二、线程池
2.1、线程池的定义和作用
学习新知识咱们照旧从定义开始;后续涉及概念类的查询推荐上wikipedia,它能提供一个相对客观的结果。本人只能求助于度娘,(摘自百度)——线程池(thread pool):一种线程使用模式。其作用是让你在项目开发中更加科学地利用多线程技术,从而提高程序的局部或整体性能、减少对系统资源的过分使用。使用线程池的好处体现在以下几个方面:
%降低资源消耗:通过复用现有的线程来执行任务,避免重复创建和销毁线程。
%提高响应速度:省去了创建线程,新任务可以立即执行。
%提供附加功能:可拓展功能,比如说定时、延时来执行某些线程。
%提高线程的可管理性:使用线程池对线程的创建、使用和销毁进行统一的分配、调优和监控。
2.2、线程池的设计与工作原理
通用线程池的结构主要包含4个角色:
①线程池管理器:维护管理线程池。
②工作线程:线程池中的线程。
③任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行。
④任务队列:用于存放没有被处理的任务。
工作原理:
①创建线程池
②将要执行的任务添加到线程池任务队列等待执行(必要时检查拒绝策略)
③工作线程不断从任务队列取出并执行
④回收线程
2.3、java线程池实现
java从1.5版本引入了并发编程大师级人物-Doug Lea的杰作“java.util.concurrent”,此包对多线程方面的功能进行了系统性的完善。今天,我们重点关注线程池相关的几个接口和类,咱们看图说话:

图中的3个接口、4个实现类、1个工具类为我们提供了使用线程池的一些简单方法。Executors是java提供的线程池工具类,可以创建以下线程池:
① newFixedThreadPool:固定大小的线程池,使用无界LinkedBlockingQueue,无界只是因为物理内存达不到。
② newCachedThreadPool:可缓存的、动态创建回收的线程池,上限为integer.max_value。
③newScheduledThreadPool:固定大小线程池,执行延迟任务或定期任务,可以指定任务的延迟时间或执行周期。
④newSingleThreadExecutor:只有一个工作线程,所有任务按照提交顺序依次执行。
其实所有的线程池最终都是通过调用ThreadPoolExecutor的构造方法来创建,我们也可以手动方式创建线程池。
下面对比不使用线程池和使用线程池来处理多任务的区别,环境:mac 2.5g,core2,4g,jdk1.6,总任务量10000个。「注:仅为了对比两种技术的性能,不考虑业务逻辑和线程同步问题。」
先贴所有代码


②不适用线程池的执行结果 ③使用线程池的执行结果

从②、③步的结果能直观看出使用线程池技术的优势,两段代码中都涉及到CPU计算和IO输出。(可利用不同的线程池来测试看看结果如何)。
三、多线程应用
多线程应用无非就是通过并行处理批量任务从而快速获取结果。以下是一些典型的场景实例:

① 会话程序——建立一个服务端程序多线程响应客户端的请求
服务端代码: 服务端处理代码:

客户端代码: 2个客户端执行结果:

② 机票销售——模拟单个航班的机票销售
国内的飞机载客量大致是160~260人/架。假设有一家飞机从上海飞往北京,经济舱有200张机票对外出售,分别有(航空公司、携程、飞猪、去哪)4家平台能对外销售机票,有300名旅客要抢购这200张机票。现在用多线程来实现这个简单的需求,图片来一波~






上述测试结果是个特例,经多次在本人电脑上运行得出结论:300个用户、200张票、4个平台,各平台的抢售成功率在18~50%。
四、总结
多线程和池化技术虽然好处多多。但是,在实际应用时也有很多需要注意的关键点。以本人经验概括总结出以下几条:

① 核心业务首选中间件的方式来处理并行任务,不推荐使用多线程技术(大神除外)。必须要使用的话继续往下;
② 线程安全问题,如无共享数据读写此条忽略;
③ 任务顺序是否存在前后依赖;
④ 如存在第2条的问题,就要使用到各种锁,必然要考虑死锁的可能性,其次就是线程数据传递和隔离问题;
⑤ 性能问题,线程切换同样会造成性能的损失。线程池的选择以及4个核心参数(核心线程数、最大线程数、线程存活时间,以及任务队列的大小)的具体配置要跟具体任务的总量相匹配;否则不会得到预期效果。



发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注