以往说到的线程对象都是java平台中非常初级的API,用于处理一些基本的任务,对于一些复杂高级的工作,就需要一些高级的并发对象,尤其是针对于大规模并发应用程序,要充分利用现在的多核多处理器系统的性能。
以下内容包括一些从java5开始java平台具有的一些高并发特性。这些特征多数在包java.util.concurrent中实现,java集合框架中也有新的并发数据结构。
锁对象
同步代码依赖于一种简单的再进入锁,这种锁比较易用,但有很多局限性,java.util.concurrent.locks包支持许多高级的锁用法,在这里集中讲其中最基本的接口Lock。
Lock对象的作用方式很像同步代码使用的隐式锁,相似之处在于一个锁对象一次只能被一个线程拥有,Lock对象也支持wait/notify机制,通过相关的Condition对象实现。
Lock对象相对于隐式锁最大的优势在于其能够收回锁的请求,调用tryLock方法请求锁时,如果锁无立即法获取或者在超时之前(如果指定)无法获取就会收回请求;调用lockInterruptibly请求锁
,如果在获得锁之前另一个线程发送中断信号,请求将被收回。
正确使用锁对象可以避免死锁的产生,即如果一个线程需要对两个对象进行同步操作,则确保同时获得两个对象的锁就可以了,tryLock的典型用法为:
Lock lock = ...;//此处省略锁的创建表达式
if (lock.tryLock()) {
try {
//如果成功获得锁情况下的操作
} finally {//操作之后释放锁
lock.unlock();
}
} else {
// 如果未能获得锁的操作
}
执行者
之前所有举的例子中,都有和一个新的线程所作的工作与线程本身的紧密联系,然而在大型的程序中,一般会将线程的管理和创建与程序的其他部分分开,而封装了这些功能的对象叫做执行者,以下将执行者分三部分:
- 执行者接口--定义三个执行者对象接口类型
- 线程池--最常用的一类执行者的实现
- Fork/Join 充分利用多处理器性能的框架(JDK7引入)
Executer接口
java.util.concurrent包中定义了三个执行者接口:
- Executor--一个支持启动新任务的简单接口
- ExecutorService--Executor的子接口,在其基础上添加了帮助管理生命周期的特性,包括个体任务和执行者本身的生命周期
- ScheduledExecutorService--ExecutorService的子接口,支持 and/or 周期性地执行任务
一般情况下,引用执行者对象的变量的类型都被声明为以上三种接口类型,而不是实现接口的类的类型。
Executor接口提供了单一的方法,execute,其被设计为一个通常的线程对象创建的替代方法,如:
//将以下线程创建方法
(new Thread(r)).start();
//替换为
e.execute(r);
//注意e是已经创建号的Executor对象
方法execute的定义不是很明确,低级的方法创建一个新线程对象后就立马开始执行,而Executor对象根据具体的实现,可能也是立即执行,但更多的时候是利用已经存在的工人线程去运行示例中的r,或者将r放在队列中等待运行(下面的线程池中会讲到)。
java.util.concurrent包中的执行者实现类是为了充分更高级的ExecutorService 和ScheduledExecutorService接口而设计的,当然也适用于基础的Executor接口。
ExecutorService接口对于execute方法补充了一个类似的,但是功能更强的submit方法,就像execute方法一样,submit方法接收Runnable对象为参数,也可以接收允许任务返回一个值的Callable对象,submit方法返回一个Future对象,该Future对象可以检索Callable对象返回的值,并可以管理Callable和Runnable任务的状态。
ExecutorService接口还提供了支持提交大量Callable对象集合的方法,最后还有许多管理执行者终结的方法,如果需要立马终结,则需要正确处理中断。
ScheduledExecutorService接口除了继承ExecutorService的特征外,还补充了schedule方法,该方法可以延迟执行Runnable和Callable对象,此外scheduleAtFixedRate和scheduleWithFixedDelay方法分别指定执行任务的重复和执行间隔。
线程池
大部分java.util.concurrent包中的执行者接口的实现类都使用线程池,线程池由多个工人线程组成,这种线程于其所执行的Runnable和Callable任务是分开的,经常被来执行多任务。
线程池的使用使线程创建的开销最小化,线程对象需要使用大量的内存,而且在大型的程序中,线程对象的分配和解除分配会带来大量的内存管理开销。
有一种常用的线程池叫固定线程池,这种线程池总是有指定数量的线程在运行,如果一个线程由于某种原因终止而线程池还在运行的时候,线程池就会自动替换新的线程。当活动的任务多余线程数量的时候,任务就会通过一个内部的队列提交到线程池。
固定线程池的重要优势就是应用程序可以利用其巧妙地降低负荷,比如一个web服务器应用程序中,每一个HTTP请求由一个独立线程处理,如果该程序对于一个新的HTTP请求只是简单地创建新的线程,随着请求量增加,系统很快就没有资源再创建更多的线程,程序因此可能会无法运行下去。当对线程创建的数量进行限制,并按照队列依次处理,程序才可能有效运行。
简单的创建一个使用固定线程池的执行者的方法就是调用java.util.concurrent.Executors的工厂方法newFixedThreadPool,这个类中也提供了以下工厂方法:
- newCatchedThreadPool方法创建一个含有可扩展线程池的执行者,该执行者适用于需要执行短时间任务的程序。
- newSingleThreadExecutor方法创建一个一次执行单个任务的执行者
当以上工厂方法不能满足需求,可以创建java.util.concurrent.ThreadPoolExecutor或者
java.util.concurrent.ScheduledThreadPoolExecutor实例以提供更丰富的功能。
Fork/Join
Fork/Join框架是一个ExecutorService
接口的实现,帮助你充分利用多处理器的性能,它是为可以递归细分的任务而设计的,目的是使用所有的可使用的处理资源来增强程序的性能。
就像其他ExecutorService接口的实现一样,fork/join框架将任务分配给线程池中的工作线程,fork/join框架与众不同的地方在于其“工作窃取“算法,已经处理完成任务的线程可以从其他正在繁忙的线程中窃取工作任务。
fork/join框架的核心是ForkJoinPool类,它是AbstractExecutorService类的扩展,ForkJoinPool类实现最核心的工作窃取算法,并且可以执行ForkJoinTask过程。
fork/join基本的用法就是先定义一个继承ForkJoinTask类或者ForkJoinTask子类的类,用于处理部分的工作,定义好类以后,实例化该类并作为参数传给ForkJoinPool
实例的invoke方法。
java se中有一些通用的特征已经用fork/join框架实现,如java8的java.util.Arrays类的parallelSort方法,这个方法与sort方法类似,但是利用了fork/join框架,在多处理器系统上,对于大型数组的并行排序比串行排序快。另外一个利用了fork/join框架的实现是java.util.streams包中的一些方法。
java-并发-高级并发对象1的更多相关文章
-
Java多线程编程核心技术---对象及变量的并发访问(一)
synchronized同步方法 "非线程安全"其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是"脏读",也就是渠道的数据其实是被更改 ...
-
Java高并发--安全发布对象
Java高并发--安全发布对象 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 发布对像:使一个对象能够被当前范围之外的对象使用. 对象逸出:一种错误的发布.当一个对象 ...
-
【Java并发.4】对象的组合
到目前为止,我们已经介绍了关于线程安全与同步的一些基础知识.然而,我们并不希望对每一系内存访问都进行分析以确保程序是线程安全的,而是希望将一些现有的线程安全组件组合为更大规模的组件或程序. 4.1 设 ...
-
java处理高并发高负载类网站的优化方法
java处理高并发高负载类网站中数据库的设计方法(java教程,java处理大量数据,java高负载数据) 一:高并发高负载类网站关注点之数据库 没错,首先是数据库,这是大多数应用所面临的首个SPOF ...
-
Java编程思想 - 并发
前言 Q: 为什么学习并发? A: 到目前为止,你学到的都是有关顺序编程的知识,即程序中的所有事物在任意时刻都只能执行一个步骤. A: 编程问题中相当大的一部分都可以通过使用顺序编程来解决,然而,对于 ...
-
JAVA的高并发基础认知 二
一.JAVA高级并发 1.5JDK之后引入高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发 ...
-
Java中多线程并发体系知识点汇总
一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...
-
[转]java处理高并发高负载类网站的优化方法
本文转自:http://www.cnblogs.com/pengyongjun/p/3406210.html java处理高并发高负载类网站中数据库的设计方法(java教程,java处理大量数据,ja ...
-
java之高并发与多线程
进程和线程的区别和联系 从资源占用,切换效率,通信方式等方面解答 线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元:而把传统的进程称为重型进程(H ...
-
JAVA 多线程和并发学习笔记(三)
Java并发编程中使用Executors类创建和管理线程的用法 1.类 Executors Executors类可以看做一个“工具类”.援引JDK1.6 API中的介绍: 此包中所定义的 Execut ...
随机推荐
-
gbd基本使用一
http://biancheng.dnbcw.info/linux/391846.html
-
MATLAB中FFT的使用方法
MATLAB中FFT的使用方法 说明:以下资源来源于<数字信号处理的MATLAB实现>万永革主编 一.调用方法X=FFT(x):X=FFT(x,N):x=IFFT(X);x=IFFT(X, ...
-
Apache2.4为什么启动报错Cannot load php5apache2_4.dll into server
最近学习php,按照书上的描述,下载好apache和php后,按照其中配置进行,结果遇到了上述问题.花费了近一个半小时的时间解决了上述问题.现把解决问题过程中看到的方法总结如下. 最先肯定是一定要注 ...
-
Muduo-Base-Exception(未完待续)
Exception类 主要功能: 能够对异常信息进行输出 能够输出调用的关系 方便我们对某些信息进行调试 系统调用:#include <execinfo.h>int backtrace(v ...
-
Java日期相关操作
1.获得日期 在旧版本 JDK 的时代,有不少代码中日期取值利用了 java.util.Date 类,但是由于 Date 类不便于实现国际化,其实从 JDK1.1 开始,就更推荐使用 java.uti ...
-
DWR整合之Servlet
DWR 与 Servlet 有 2 个 Java 类你一般需要用在 DWR 中,是 webContext 和 WebContextFactory 在 DWR 1.x 它们在 uk.ltd.getahe ...
-
php类与构造函数解析
关于类大家都有一定的认识这里只介绍在php中类值得注意的地方----类的创建----php使用关键字class创建一个类,并且使用一对大括号如: class name{ public $n=" ...
-
Linux - 简明Shell编程08 - 函数(Function)
脚本地址 https://github.com/anliven/L-Shell/tree/master/Shell-Basics 示例脚本及注释 #!/bin/bash function Check( ...
-
MySQL之数据库和表的基本操作(建立表、删除表、向表中添加字段)
介绍关于数据库和表的一些基本操作 添加字段.给字段添加注释 ); ) COMMENT '统一社会信用代码录入单位'; ,) 更改字段类型 ,) COMMENT '一头签收,@0或空不用,1必须'; 有 ...
-
基于python的OpenCV图像1
目录 1. 读入图片并显示 import cv2 img = cv2.imread("longmao.jpg") cv2.imshow("longmao", i ...