在java3以前java没有提供线程安全的集合对象,之后有了很多,如 ConcurrentLinkedQueue、ConcurrentHashMap
集合对象往往用于缓存对象,特别是在服务器中,很大程度的提升服务的效率,他一般都被设计为共享资源。多线程环境下,对象共享需要加上锁,以保证线程安全。
我们可以如下设计
<span style="font-size:18px;">public class resource {
private String name;
private int xx;
public synchronized String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
public synchronized int getXx() {
return xx;
}
public synchronized void setXx(int xx) {
this.xx = xx;
}
}</span>
以上设计,用到了resource实例的锁,他能很好的解决name ,xx存取同步的问题。
但是,在很多情况下,resource是不能这么设计的,synchronized关键字让设计变得非常的复杂,并且对name ,xx的访问都不能异步了,
大部分情况下,我们这样设计:如果对象要求被共享,我们则把对象放入同步的环境中。
<span style="font-size:18px;">import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class resource {
private Lock lock_Name = new ReentrantLock();
private Lock lock_xx = new ReentrantLock();
private String name;
private int xx;
public String getName() {
try {
lock_Name.lock();
return name;
}finally{
lock_Name.unlock();
}
}
public void setName(String name) {
try {
lock_Name.lock();
this.name = name;
}finally{
lock_Name.unlock();
}
}
public int getXx() {
try {
lock_xx.lock();
return xx;
}finally{
lock_xx.unlock();
}
}
public void setXx(int xx) {
try {
lock_xx.lock();
this.xx = xx;
}finally{
lock_xx.unlock();
}
}
}</span>
name 、xx都是要被共享的资源,但是彼此有不同的同步环境。
这也让我们想到了锁粒度的问题,粒度越小这会让程序性能更好,并且尽量的避免资源的竞争,是提高性能、预防死锁的设计结构
前面锁的粒度很大,resource实例会锁住所有的资源。后面的例子中锁则是每个资源都有一独立的锁。后面的设计更加的合理些。
回到java的集合对象,集合中有很多资源,要被共享的资源通常是集合中的“列表(数组)”,所以集合通常只对其中的“列表”加锁,而不会对其他的属性加锁,就算需要共享其他属性,也要加其他的锁,而不是统一用集合对象的锁。