Java集合~ConcurrentHashMap原理

集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支持。比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap)。文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅。

通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

采用静态ConcurrentHashMap处理缓存:http://blog.csdn.net/dreamthen/article/details/14125245

建立一个bean:

@LocalBean

@Singleton

@ConcurrencyManagement(ConcurrencyManagementType.BEAN)

public class LoanBridge {

private final ConcurrentHashMap<String, LoanExt> finishedLoans = new ConcurrentHashMap<>();

//初始化finishedLoans

@PostConstruct

public void init() {

}

}

被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。PreDestroy()方法在destroy()方法执行执行之后执行

项目启动时此bean会默认加载,这样其他类调用此bean时可直接用finishedLoans

如果一个session bean被定义成@Singleton的话,是由EJB容器,也就是glassfish在启动的时候去进行初始化的,仅维护一个实例,所以像ApplicationBean用到全局变量,还有一些有定时任务的bean,都被@Singleton了。ConcurrencyManagementType.BEAN是由开发者去管理并发控制,所以可以看到这些bean有许多方法被
synchronized修饰。

@Asynchronous

private synchronized void updateScheduledAndOpen() {

}

ejb中通过锁机制也可以达到这种效果:

@LocalBean

@Singleton

@ConcurrencyManagement(ConcurrencyManagementType.BEAN)

public class CorporationBridge {

@EJB

ApplicationBean appBean;

@EJB

CorporationUserService corporationService;

private Set<String> legalPersons = new HashSet<>();

@PostConstruct

void init() {

triggerUpdate();

}

@Lock(LockType.WRITE)

public void triggerUpdate() {

legalPersons.clear();

legalPersons = new HashSet<>(corporationService.listLegalPerson(appBean.getClientCode()));

}

以下供参考:ConcurrencyManagementType的两种类型注释,Container与Bean

Stateless(无状态的) EJB‘s

Even though Stateless EJB‘s may never be concurrently accessed by more than a single client call, this article would be otherwise incomplete if it did not mention this kind of EJB‘s.

Stateless EJB‘s are pooled by the container. Every time a client makes a call to a Stateless EJB, the container will fetch an available instance from the pool to handle the client request. When that instance is
handling the client request, that same instance will not handle any other call that is made from any given client. When that call ends, the EJB instance is returned to the pool and becomes once again available to handle client requests.

If there is no available EJB instance in the pool to handle a client request (ex: the pooled EJB instances are all busy handling other requests), the container will create a new instance, put it in the pool, and
let it handle the incoming client request.

This pool is usually configured by application server, and if it becomes exhausted when a client request arrives (ex: the pool has reached its maximum size) an exception will be thrown and propagated to the remote
client.

Even if there are multiple consecutive calls from the same client to the same Stateless EJB, it should never be assumed that those consecutive calls will be handled by the same EJB instance.

Stateless EJB

@Stateless
public class StatelessEJB {

  public void doSomething(){

  }

}

EJB client

@EJB
private StatelessEJB statelessEJB;

public void clientMethod() {

  // These consecutive calls are NOT guaranteed to
  // be handled by the same Stateless EJB instance
  statelessEJB.doSomething();
  statelessEJB.doSomething();

}

Container managed concurrency(容器管理并发)

As opposed to Stateless EJB‘s, Singleton and Stateful EJB‘s may be configured to handle concurrent requests from any given client.

Container managed concurrency configuration applies both to Singleton and Stateful(有状态的) EJB‘s - keep in mind that Stateful EJB‘s concurrency strategy will always consist in WRITE (exclusive)
locking semantics. It allows, in conjunction with Lock and LockType primitives, to configure how concurrent access should be allowed by the container while handling EJB calls, with method level granularity:

Singleton EJB

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class SingletonEJB {

  int counter;

  @Lock(LockType.READ)
  public int readCounter() {
    return counter;
  }

  @Lock(LockType.WRITE)
  public void incrementCounter() {
    counter++;
  }

}

By default, every Stateful and Singleton EJB has container managed concurrency so, in this example, the annotation@ConcurrencyManagement with its value defined as CONTAINER is
redundant(默认是container,此处标记是冗余的).

Note: Stateful EJB‘s container managed concurrency will always have WRITE locking semantics. READ locking semantics apply only to Singleton EJB‘s.

The Lock annotation may have a couple of distinct values: READ and WRITE. Methods annotated with READ lock type may be accessed
concurrently by any arbitrary number of clients, given the fact that there is no method configured with WRITE lock type being accessed at that moment.(读的时候确保不能有写的线程在执行)

WRITE lock type methods are exclusive, ie. if a WRITE locked method is being accessed at a given moment, no other method - READ or WRITE - may be accessed until the method execution completes.
Since WRITE methods are exclusive, if a WRITE method is ready to be executed but there is(are) other method(s) executing at that time, it must wait for the them to complete in order to acquire the exclusive lock and proceed.(写的时候,不能有其他线程读或者写,必须等待当前线程完成执行)

It‘s important to mention that the Lock annotation may also be defined at class level, meaning that the specified access type will then be applied to all EJB methods. We
may override the behavior for specific methods by applying the annotation to a given method:(锁可以加在类层级,也可以加在方法层级)

Singleton EJB (Lock configuration at class level)

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Lock(LockType.READ)
public class SingletonEJB {

  int counter;

  // This method will inherit the Lock
  // configuration defined at class level
  public int readCounter() {
    return counter;
  }

  // This method overrides the class level
  // Lock semantics by changing it to WRITE
  @Lock(LockType.WRITE)
  public void incrementCounter() {
    counter++;
  }

}

Note: By default, every Singleton EJB has container managed concurrency with WRITE lock semantics for all methods. You really should take a look into your EJB‘s and see if this is in fact the desired behavior. If
you have methods that, for example, should be allowed to execute concurrently because they do not modify the EJB instance state, maybe you could configure them with READ lock semantics (otherwise you end up with a serialized access bottleneck even in read
operations).

We end this section mentioning the access timeout configuration. One may additionally configure the amount of time that a client request will wait for concurrent method access, before giving
up. Once the timeout is reached, the container will throw an exception which will be propagated to the calling client. The timeout is configured by the @AccessTimeout annotation, which may be defined at both class and method level (the
method level configuration overrides the class level configuration):

AccessTimeout configuration

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@AccessTimeout(value = 5000)
public class SingletonEJB {

  int counter;

  @Lock(LockType.READ)
  @AccessTimeout(value = 2, unit = TimeUnit.SECONDS)
  public int readCounter() {
    return counter;
  }

  @Lock(LockType.WRITE)
  public void incrementCounter() {
    counter++;
  }

}

The Access Timeout annotation may be configured with value and unit properties: the value property specifies the amount of time before the timeout
is reached, while the unit - as the name states - specifies the unit in which the time property value is defined. The default time unit is MILLISECONDS.

In this example, the incrementCounter() method will have a timeout of 5 seconds (inherited from the class level configuration), while the method readCounter() will
have a timeout of 2 seconds (overriding the class level configuration).

Bean managed concurrency(Bean管理并发)

As the ConcurrencyManagement
documentation
 states, bean managed concurrency is only applied to Singleton EJB‘s.

Bean managed concurrency is defined like the following:

Bean managed concurrency Singleton EJB

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class SingletonEJB {

  public void someMethod() {

  }

}

Bean managed concurrency means that no Java EE primitives, like Lock and LockType, may be used to manage concurrent access to a given Singleton EJB. The application is instead responsible
to manage concurrent access by the means of the traditional concurrent access primitives, like synchronized, volatile, wait, notify or
any other data structure or library that provides concurrent access management.(由开发者去管理并发控制,这段话自己揣摩,大致意思是Bean类型修饰的控制权限问题,我也翻译不好)

时间: 2024-08-29 18:37:40

Java集合~ConcurrentHashMap原理的相关文章

Java集合---ConcurrentHashMap原理分析

集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅. 通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张

2.Java集合-ConcurrentHashMap实现原理及源码分析

一.为何用ConcurrentHashMap 在并发编程中使用HashMap可能会导致死循环,而使用线程安全的HashTable效率又低下. 线程不安全的HashMap 在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap 效率低下的HashTable Hashtable使用synchronized来保证线程的安全,但是在线程竞争激烈的情况下Hashtable的效率非常低下.当一个线程访问Hashtable的同步方法,

Java集合——ConcurrentHashMap

集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅. 首先比较一下HashMap,CurrentHashMap,HashTable HashMap不是

Java 中 ConcurrentHashMap 原理分析

一.Java并发基础 当一个对象或变量可以被多个线程共享的时候,就有可能使得程序的逻辑出现问题. 在一个对象中有一个变量i=0,有两个线程A,B都想对i加1,这个时候便有问题显现出来,关键就是对i加1的这个过程不是原子操作.要想对i进行递增,第一步就是获取i的值,当A获取i的值为0,在A将新的值写入A之前,B也获取了A的值0,然后A写入,i变成1,然后B也写入i,i这个时候依然是1. 当然java的内存模型没有上面这么简单,在Java Memory Model中,Memory分为两类,main

深入java集合系列文章

搞懂java的相关集合实现原理,对技术上有很大的提高,网上有一系列文章对java中的集合做了深入的分析, 先转账记录下 深入Java集合学习系列 Java 集合系列目录(Category) HashMap深度解析 Java 理论与实践: 并发集合类 Java集合---ConcurrentHashMap原理分析 java主要集合类的数据结构学习 Java并发集合的实现原理 -..

1.Java集合-HashMap实现原理及源码分析

哈希表(Hash  Table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出现在各类的面试题中,这里对java集合框架中的对应实现HashMap的实现原理进行讲解,然后对JDK7的HashMap的源码进行分析 哈希算法,是一类算法: 哈希表(Hash  Table)是一种数据结构: 哈希函数:是支撑哈希表的一类函数: HashMap 是 Java中用哈希数据结构实现的Ma

【转】Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)

概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例3 fail-fast解决办法4 fail-fast原理5 解决fail-fast的原理 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3308762.html 1 fail-fast简介 fail-fast 机制是java集合(Collection)中

深入Java集合学习系列:HashMap的实现原理

参考文献 引用文献:深入Java集合学习系列:HashMap的实现原理,大部分参考这篇博客,只对其中进行稍微修改 自己曾经写过的:Hashmap实现原理 1. HashMap概述: HashMap是基于哈希表的Map接口的非同步实现(Hashtable跟HashMap很像,唯一的区别是Hashtalbe中的方法是线程安全的,也就是同步的).此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变. 2. HashMap的数据结构: 在ja

Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)

概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例3 fail-fast解决办法4 fail-fast原理5 解决fail-fast的原理 转载:http://www.cnblogs.com/skywang12345/p/3308762.html 1 fail-fast简介 fail-fast 机制是java集合(Collection)中的一种错误

Java集合---ArrayList的实现原理

一. ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小.   每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小.它总是至少等于列表的大小.随着向ArrayList中不断添加元素,其容量也自动增长.自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容