yuyee

2010年11月8日 #

适配器

适配器模式:将一个现有类实现的功能接口转变为客户希望的接口

场景:你想使用一个已经存在的类,但是这个类的接口不符合需求,所以需要适配

2中实现:一种是继承,一种是委托,先来看看继承

   

第一步:系统现有功能

package com.google.desginpattern.adapter;
/**
 * 现有系统提供的功能
 * 
 * 
@author Administrator
 * 
 
*/
public class BMWCar {
public void quickDriver() {
System.out.println(
"宝马太快");
}
}

 

第二步:客户需要的接口

package com.google.desginpattern.adapter;
/**
 * 客户需要的接口
 * 
@author Administrator
 *
 
*/
public interface Car {
public void driver();
public void brake();
}

 

第三步:实现客户需要的功能

package com.google.desginpattern.adapter;
/**
 * 匹配客户需求的实现
 * 
@author Administrator
 *
 
*/
public class CarAdapter extends BMWCar implements Car {
@Override
public void brake() {
System.out.println(
"刹车");
}
@Override
public void driver() {
quickDriver();
}
}

 

测试类:

 

package com.google.desginpattern.adapter;


public class Test {

public static void main(String[] args) {


Car car 
= new CarAdapter();

car.brake();

car.driver();

}


}

输出:

刹车

宝马太快

如果是委托的方式,改写adapter

package com.google.desginpattern.adapter;
/**
 * 匹配客户需求的实现
 * 
 * 
@author Administrator
 * 
 
*/
public class CarAdapter implements Car {
private BMWCar car;
@Override
public void brake() {
System.out.println(
"刹车");
}
@Override
public void driver() {
car.quickDriver();
}
public BMWCar getCar() {
return car;
}
public void setCar(BMWCar car) {
this.car = car;
}
}

 

posted @ 2010-11-29 22:28 羔羊| 编辑 收藏

装饰器


装饰器:装饰器模式主要用于系统扩张功能用,在系统原有的功能上,扩展出其他的功能,JDKIO包用到很多,比如datainputstream之类,需要用其他流进行构造的上层类,符合面向对象设计的开闭原则

下面我来写个例子:

首先,写一个Car模版,定义基本属性及行为功能driver

package com.google.desginpattern.decoration;
//其实这是个模版
public abstract class Car {
private int spreed;
public int getSpreed() {
return spreed;
}
public void setSpreed(int spreed) {
this.spreed = spreed;
}
public abstract void driver();
}

 

第二步:具体车比如宝马,这是目前系统中这个类能提供的功能

package com.google.desginpattern.decoration;
//目前系统中此类的功能
public class BMWCar extends Car {
@Override
public void driver() {
System.out.println(
"我开着宝马车");
}
}

 

现在我想在这个类上扩展出其他功能,比如:泡妞

第三步:定义一个装饰模板,为什么给他定义个模板呢~因为可以给这个BMWCar类装饰很不同的功能,不只泡妞一个~

继承Car父类,覆盖driver功能,调用Car引用完成driver功能

package com.google.desginpattern.decoration;
//装饰器父类
public abstract class DecorationCar extends Car {
// 引入car
private Car car;
@Override
public void driver() {
car.driver();
// 调用此car来完成装饰器的功能
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}

 

第四步:具体的装饰功能,添加一个构造函数,参数为Car,为装饰父类Car引用赋值,其实就是原来具体的功能类,回想下IO包里经常new的代码段就明白~~

package com.google.desginpattern.decoration;
//具体的装饰类,添加额外的泡妞功能
public class DecorationBMWCar extends DecorationCar {
public DecorationBMWCar(Car car) {
super.setCar(car);
}
@Override
public void driver() {
// TODO Auto-generated method stub
super.driver();// 调用原来的功能
System.out.println("泡妞");// 添加额外的功能
}
}

 

测试类:构造的方法很像IO包里的流

package com.google.desginpattern.decoration;
public class Test {
public static void main(String[] args) {
Car car 
= new DecorationBMWCar(new BMWCar());
car.driver();
}
}

 

输出:

我开着宝马车

泡妞

posted @ 2010-11-29 21:36 羔羊| 编辑 收藏

IOC初始化和互相引用解决

     摘要: 观察IOC中容器初始化某个Bean顺序,现先一个JAVABean类,看看控制台输出:package com.google.aop.exception.ioc; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory...  阅读全文

posted @ 2010-11-10 16:27 羔羊| 编辑 收藏

AbstractQueuedSynchronizer看看


API中的解释:为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁定和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()getState()getState()setState(int)compareAndSetState(int, int) 方法来操作以原子方式更新的 int 值。
此类采用模板模式设计,此类为一个抽象类,但是没抽象方法,每个sync子类需要实现5个受保护的方法

这个5个方法在AbstractQueuedSynchronizer 都抛出throw new UnsupportedOperationException();
AbstractQueuedSynchronizer 中有3个属性:主要声明一个状态和一个wait queue,通过

wait queue中Node 为一个双向链表,需要去理解Node中几个静态字段值的意义,下面为他的源码:
static final class Node {
        /** waitStatus value to indicate thread has cancelled */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /** Marker to indicate a node is waiting in shared mode */
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
        static final Node EXCLUSIVE = null;

        /**
         * Status field, taking on only the values:
         *   SIGNAL:     The successor of this node is (or will soon be)
         *               blocked (via park), so the current node must
         *               unpark its successor when it releases or
         *               cancels. To avoid races, acquire methods must
         *               first indicate they need a signal,
         *               then retry the atomic acquire, and then,
         *               on failure, block.
         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
         *               Nodes never leave this state. In particular,
         *               a thread with cancelled node never again blocks.
         *   CONDITION:  This node is currently on a condition queue.
         *               It will not be used as a sync queue node until
         *               transferred. (Use of this value here
         *               has nothing to do with the other uses
         *               of the field, but simplifies mechanics.)
         *   0:          None of the above
         *
         * The values are arranged numerically to simplify use.
         * Non-negative values mean that a node doesn't need to
         * signal. So, most code doesn't need to check for particular
         * values, just for sign.
         *
         * The field is initialized to 0 for normal sync nodes, and
         * CONDITION for condition nodes.  It is modified only using
         * CAS.
         */
        volatile int waitStatus;

        /**
         * Link to predecessor node that current node/thread relies on
         * for checking waitStatus. Assigned during enqueing, and nulled
         * out (for sake of GC) only upon dequeuing.  Also, upon
         * cancellation of a predecessor, we short-circuit while
         * finding a non-cancelled one, which will always exist
         * because the head node is never cancelled: A node becomes
         * head only as a result of successful acquire. A
         * cancelled thread never succeeds in acquiring, and a thread only
         * cancels itself, not any other node.
         */
        volatile Node prev;

        /**
         * Link to the successor node that the current node/thread
         * unparks upon release. Assigned once during enqueuing, and
         * nulled out (for sake of GC) when no longer needed.  Upon
         * cancellation, we cannot adjust this field, but can notice
         * status and bypass the node if cancelled.  The enq operation
         * does not assign next field of a predecessor until after
         * attachment, so seeing a null next field does not
         * necessarily mean that node is at end of queue. However, if
         * a next field appears to be null, we can scan prev's from
         * the tail to double-check.
         */
        volatile Node next;

        /**
         * The thread that enqueued this node.  Initialized on
         * construction and nulled out after use.
         */
        volatile Thread thread;

        /**
         * Link to next node waiting on condition, or the special
         * value SHARED.  Because condition queues are accessed only
         * when holding in exclusive mode, we just need a simple
         * linked queue to hold nodes while they are waiting on
         * conditions. They are then transferred to the queue to
         * re-acquire. And because conditions can only be exclusive,
         * we save a field by using special value to indicate shared
         * mode.
         */
        Node nextWaiter;

        /**
         * Returns true if node is waiting in shared mode
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * Returns previous node, or throws NullPointerException if
         * null.  Use when predecessor cannot be null.
         * @return the predecessor of this node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }


    }
获取锁定调用的方法,其实这个方法是阻塞的:
  public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
如果获取不成功则调用如下方法:
   final boolean acquireQueued(final Node node, int arg) {
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {//当节点是头节点且独占时才返回
                    setHead(node);
                    p.next = null; // help GC
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//阻塞并判断是否打断,其实这个判断才是自旋锁真正的猥琐点,
意思是如果你的前继节点不是head,而且当你的前继节点状态是Node.SIGNAL时,你这个线程将被park(),直到另外的线程release时,发现head.next是你这个node时,才unpark,你才能继续循环并获取锁
                    interrupted = true;
            }
shouldParkAfterFailedAcquire这个方法删除所有waitStatus>0也就是CANCELLED状态的Node,并设置前继节点为signal
 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int s = pred.waitStatus;
        if (s < 0)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park
             */
            return true;
        if (s > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
   do {
node.prev = pred = pred.prev;
   } while (pred.waitStatus > 0);
   pred.next = node;
}
        else
            /*
             * Indicate that we need a signal, but don't park yet. Caller
             * will need to retry to make sure it cannot acquire before
             * parking.
             */
            compareAndSetWaitStatus(pred, 0, Node.SIGNAL);
        return false;
    }


使用LockSupport.park(this),禁用当前线程
private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);//block
        return Thread.interrupted();
    }
释放锁:
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);//unblock
            return true;
        }
        return false;
    }
private void unparkSuccessor(Node node) {
        /*
         * Try to clear status in anticipation of signalling.  It is
         * OK if this fails or if status is changed by waiting thread.
         */
        compareAndSetWaitStatus(node, Node.SIGNAL, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }


        } catch (RuntimeException ex) {
            cancelAcquire(node);
            throw ex;
        }
    }
  

看下ReentrantLock锁中sync的实现:
 static abstract class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is
         * implemented in subclasses, but both need nonfair
         * try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes this lock instance from a stream.
         * @param s the stream
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }
非公平规则下nonfairTryAcquire,获取当前锁的state,通过CAS原子操作设置为1,并将当前线程设置为独占线程,如果当前线程已经拿了锁,则state增加1
公平锁中 有如下判断:
if (isFirst(current) &&//判断头元素
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
在获取锁步骤:
1.调用tryAcquire来获取,如果失败,则进入2
2.调用addWaiter,以独占模式将node放到tail位置
3.调用acquireQueued方法,此方法阻塞,直到node的pre为head,并成功获取锁定,也可能存在阻塞并打断情况
释放锁的步骤:
1.放弃排他锁持有权
2.unpark 节点的下一个blocked节点

公平锁与非公平锁:从代码上看,非公平锁是让当前线程优先独占,而公平锁则是让等待时间最长的线程优先,非公平的可能让其他线程没机会执行,而公平的则可以让等待时间最长的先执行,但是性能上会差点

posted @ 2010-11-09 15:30 羔羊| 编辑 收藏

linkedhashmap看看

linkedhashmap继承自hashmap,他的底层维护的一个链表,    private transient Entry<K,V> header 来记录元素的插入顺序和访问顺序;
hashmap的构造函数中调用init()方法,而linkedhashmap中重写了init(),将head元素初始化
   void init() {
        header = new Entry<K,V>(-1, null, null, null);
        header.before = header.after = header;
    }

private final boolean accessOrder这个属性表示是否要根据访问顺序改变线性结构
在linkedhashmap中改写了hashmap的get()方法,增加了 e.recordAccess(this),这个方法主要是根据accessOrder的值判断是否需要实现LRU,
 void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }

addBefore这个方法是把刚访问的元素放到head的前面
 private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }
put方法继承自hashmap,hashmap预留了 e.recordAccess(this)这个方法:
     public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

并通过重写 addEntry(hash, key, value, i)这个方法,实现LRU中的删除动作:
    void addEntry(int hash, K key, V value, int bucketIndex) {
        createEntry(hash, key, value, bucketIndex);

        // Remove eldest entry if instructed, else grow capacity if appropriate
        Entry<K,V> eldest = header.after;//找到最老的元素,这个在addBefore里确定,初次赋值是当只有一个head时候,你插入一个元素
        if (removeEldestEntry(eldest)) {//这个是受保护的方法,需要自己制定删除策略,比如size() > 最大容量,可自己实现,默认为false,也就是不开启
            removeEntryForKey(eldest.key);
        } else {
            if (size >= threshold)
                resize(2 * table.length);
        }
    }
自己重写这个方法,指定删除策略:
 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }
因此,可用linkedhashmap 构建一个基于LRU算法的缓存。


package com.google.study.cache;

import java.util.LinkedHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class SimpleCache<K, V> extends LinkedHashMap<K, V> {

private int maxCapacity;
private ReentrantLock lock = new ReentrantLock();

public SimpleCache(int maxCapacity, float load_factory) {
super(maxCapacity, load_factory, true);
this.maxCapacity = maxCapacity;
}

public int getMaxCapacity() {
return maxCapacity;
}

public void setMaxCapacity(int maxCapacity) {
this.maxCapacity = maxCapacity;
}

@Override
protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
// TODO Auto-generated method stub
return super.removeEldestEntry(eldest);
}

public V get(Object key) {
lock.lock();
try {
return super.get(key);
} finally {
lock.unlock();
}

}

public V put(K k, V v) {
lock.lock();
try {
return super.put(k, v);
} finally {
lock.unlock();
}
}

@Override
public void clear() {
lock.lock();
try {
super.clear();
} finally {
lock.unlock();
}
}

@Override
public int size() {

lock.lock();
try {
return super.size();
} finally {
lock.unlock();
}
}

}



posted @ 2010-11-08 23:14 羔羊| 编辑 收藏