java并发编程实践(4)

来源:互联网 发布:搜索合作网络关闭 编辑:程序博客网 时间:2024/06/03 18:53

1、扩展ThreadPoolExecutor该类中的beforeExcute(任务执行前被调用)、afterExecute(任务执行后被调用,无论是否正常被执行,抛出异常也会被执行)、terminated(线程池完成关闭时执行)方法可在子类中被改写;
2、锁顺序死锁:多个线程以不同的顺序获得多个对象的锁时发生死锁的现象;eg:

/*线程1:*/synchronized(obj1){    synchronized(obj2){    /*语句块*/    }}/*线程2:*/synchronized(obj2){    synchronized(obj1){    /*语句块*/    }}

此时如果线程1获得obj1的锁而线程2 获得obj2的锁,那么会形成死锁;
如果以相同的顺序获取锁,死锁问题就能得到解决:

/*线程1:*/synchronized(obj1){    synchronized(obj2){    /*语句块*/    }}/*线程2:*/synchronized(obj1){    synchronized(obj2){    /*语句块*/    }}

3、开放调用
如果调用某个方法时不需要持有锁,这种方式称作开放调用;

/*协作对象之间产生死锁**/class A {   private B b = new B();   public synchronized void a(){       /*需要同步的重要代码*/        b.b();   }   public synchronized void c(){   }}class B{   private A a = new A();   public synchronized b(){   }   pubic synchronized d(){        /*需要同步的重要代码*/        a.c();   }}

如果对象之间存在协作,当线程1调用class B的d()方法时,此时线程1可能获得两个锁,如果线程2调用class A的a()方法,此时线程2也有可能获得两个锁,当且仅当线程1没获得锁时这个可能性才成立,若线程1获得class B的锁而线程2获得class A的锁,那么此时会发生死锁现象;
采用开放调用的方式可以解决这个问题:

/*开放调用**/class A {   private B b = new B();   public void a(){        synchronized(this){          /*需要同步的重要代码*/        }        b.b();   }   public synchronized void c(){   }}class B{   private A a = new A();   public synchronized b(){   }   pubic  d(){       synchronized(this){          /*需要同步的重要代码*/        }        a.c();   }}

此时调用外部方法时,线程已经没有持有锁,因此不会发生死锁的现象。
4、减小锁的竞争
1)、减小锁的范围(”快进快出”),比如如果采用synchronized关键字修饰整个方法,资源就被线程独占,若方法体执行时间长,影响整个程序的性能,若果我们将方法中需要同步的代码用synchronized同步,则可能能减少线程对当前资源的持有时间;
2)、减小锁的粒度
ArrayBlockingQueue不支持同时读写,其底层实现使用了ReextranLock锁,类似synchronized方法会被调用线程独占,而LinkedBlockingQueue减小了锁的粒度,其实现对读操作和写操作分别用了不同的锁,所以可以同时读写操作

public class LinkedBlockingQueue<T>{      Lock write = new ReextranceLock();      Lock read= new ReextranceLock();      /*读操作*/      public T take(){       write.lock();       /**其他代码省略**/      }      /*写操作*/      public void put(T e){       read.lock();       /**其他代码省略**/      }}

3)、锁分段
将锁使用在一组独立的对象上,如ConcurrentHashMap;其使用的是散列数据结构,每个桶位独占一把锁,因此可以支持多线程并发访问;其伪代码如下:

public class ConncurrentHashMapTest{ private static final INI_LOCK = 16; private final Node[] bucket; private final Object[] lock; private static Node{    /*省略*/ } public Object get(Object key){   int i = hash(key);   synchronized(lock[i]){        /*省略*/   } }}
原创粉丝点击