jp.terasoluna.fw.web.thin.LimitedLock.java Source code

Java tutorial

Introduction

Here is the source code for jp.terasoluna.fw.web.thin.LimitedLock.java

Source

/*
 * Copyright (c) 2011 NTT DATA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.terasoluna.fw.web.thin;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * ?bNXbh???A?bNXbhf@\??bNNX?B
 * <p>
 * Web?AZbV???Asynchronized?A ??s?[U???A Xbh?L(Xbh?bN?)?B<br>
 * <ol>
 * <li>[X|X???s</li>
 * <li>X|X?A??ACgbvy?[W<br>
 * (ZbV?A1???I\)</li>
 * <li>gbvy?[W\?A??[hJ?B</li>
 * </ol>
 * <br>
 * ??s???A2?NGXg???bNXbh?A 3JNGXg?A?NGXgO???bNXbh?A
 * ???AX|XNCAgf?A?bNf?B<br>
 * f@\?ANX?B
 * </p>
 * <p>
 * NX{I?[?B<br>
 * <ul>
 * <li>?bNv?Xbh?A?bNf?B</li>
 * <li>?bNXbh?AXbh??B</li>
 * <li>?bNfXbh?A?bNXbh?A?bNXbh(Xbh?A??bNXbh)?B</li>
 * </ul>
 * (NXO?Xe?[^X???O?B?A?Xe?[^X?Xbh?bN???AX?[p?[NX@\?A?bNf?B)
 * </p>
 * <p>
 * NX{I??B<br>
 * <ul>
 * <li>?bNXbh?l??A Xbh?bNv??A?bNO?A lXbh?A?bNXbhf?B</li>
 * </ul>
 * </p>
 * <p>
 * ) l2<br>
 * Xbh1, 2, 3, 4??bNv????A Xbh1?bN?AXbh2, 3, 4?bN?B<br>
 * ?A?bNXbh(3)l(2)?A Xbh5?bNv??A ?bNXbh?AXbh2?bNf?A Xbh5?bN??B<br>
 * </p>
 * <p>
 * ?bNXbh?bN?A Xbh??A?X?bNv???(?sv???)?A ?bNXbh??Al?Al?{1J?B<br>
 * ?A?V?bNv??A?bNXbh??Al?{1?B<br>
 * ?A?sv????A?bNXbh????B<br>
 * ?AO?B<br>
 * (?A?Xbh?bN??ANXI?B)<br>
 * ?A?bNXbh???AxXgGtH?[g?B<br>
 * </p>
 * <p>
 * NX?AlockInterruptibly?\bh?bN?A unlock?\bh?bN?B<br>
 * ?bN??\bh(X?[p?[NXp?\bh)gp?B
 * </p>
 * <p>
 * ?bNfXbh?A lockInterruptibly?\bh?s?AInterruptedException??A ?bN?A?B
 * </p>
 * <p>
 * NXf(Xbh?)@?\?AInterruptedException????A Xbh?Xe?[^XNA?B<br>
 * ?ANXOXbh????ANX??? Xbh?Xe?[^Xs?B<br>
 * O?^C~O?A InterruptedException??A?Xe?[^X???B
 * (InterruptedException??A?Xe?[^XNAR?[h?s?AO????Y?B)
 * </p>
 * <p>
 * R?[hL?q?F<br>
 * <code><pre>
 * LimitedLock lock;
 * ?c LLimitedLockCX^X
 * try {
 *     lock.lockInterruptibly();
 *     ?c ?bN??
 * } catch (InterruptedException e) {
 *     ?c ?bNf??
 * } finally {
 *     lock.unlock(); // ?bN?sOsv?B()
 * }
 * </pre></code>
 * </p>
 * <p>
 * NX?AX?[p?[NXSerializable?A\?Ag?ANXI?o\???AVACY/fVACYgp???B
 * (ZbVi[???B) ?AfVACY?AX?[p?[NXl?AVACY??A?bN???B
 * </p>
 * @see ReentrantLock
 */
public class LimitedLock extends ReentrantLock {

    /**
     * VAo?[WID
     */
    private static final long serialVersionUID = 894432960610700290L;

    /**
     * ?ONX?B
     */
    private static final Log log = LogFactory.getLog(LimitedLock.class);

    /**
     * ?bNIuWFNg?B
     */
    private transient Object lock = new Object();

    /**
     * l
     */
    private int threshold;

    /**
     * ?bN???List?B<br>
     * List?A??p?AListXbh??bN?B<br>
     * (Listadd?bN?A??bNXbh?A?bN?bNXbh?B)
     */
    private transient LinkedList<Thread> waitingThreadList = new LinkedList<Thread>();

    /**
     * RXgN^?B
     * @param threshold l(0???A0)
     */
    public LimitedLock(int threshold) {
        if (threshold > 0) {
            this.threshold = threshold;
        } else {
            this.threshold = 0;
        }
    }

    /**
     * ?bN?B
     * <p>
     * ?Xbh?bN?AXbh?Xbh??s?A?Xbh@?B<br>
     * ?Xbh?bN???A?\bhA?B<br>
     * Xbh?Xbh??s???AInterruptedExceptionX??[?A?Xbh?Xe?[^XNA?B<br>
     * (?ANXO????A?Xe?[^Xs?B)
     * </p>
     * <p>
     * ?L?AX?[p?[NX?Bg|Cg?B<br>
     * <ul>
     * <li>?bNXbh?l??\bh?s?A?bNO?AlXbh?A?bNXbhf?B<br>
     * ?bNXbh?\bh?s(??bN)?A?bNXbh??AXbhf?s?B</li>
     * </ul>
     * </p>
     * @throws InterruptedException ?Xbh????(NX@\?A?bNf??)
     * @see java.util.concurrent.locks.ReentrantLock#lockInterruptibly()
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {
        boolean successToLock = false;
        // ?bNXbh????A
        // ?VXbh?bNv??A
        // ?bNXbh??B
        // (?bN?Xbh?AI?bN(??bN)|???A
        // ?bNXbh??B)
        if (getOwner() != Thread.currentThread()) {
            synchronized (lock) {
                // u?bN???Asuper.unlock();?s?A?bNXbh?bN?B
                // Xbh?bN???A
                // ?bNXbh?bN?A
                // Xbh?A?J?A?bN?oR?bN??A
                // ?bN?\bhXbh?A??Xbh?B
                // ?AXbh?bN??A
                // ?Au?bN?Asuper.lockInterruptibly();?sOXbh????A
                // Xbh?Au?bN???A??????
                // (?bNXbh???AXbh?A??)?A
                // Xbh?bN??A?bNv?Xbh?l??A
                // ??@?Ax??B
                int queueLength = getQueueLength();
                if (queueLength > threshold) {
                    HashSet<Thread> oldWaitingThreadSet = null;
                    synchronized (waitingThreadList) {
                        List<Thread> oldWaitingThreadList = waitingThreadList.subList(0, queueLength - threshold);
                        oldWaitingThreadSet = new HashSet<Thread>(oldWaitingThreadList);
                    }
                    // waitingThreadListXbh?A
                    // ??bNXbh?A
                    // ??bNXbhXg?A
                    // oldWaitingThreadListoldWaitingThreadSet?AgetQueuedThreads()?B
                    for (Thread queuedThread : getQueuedThreads()) {
                        if (oldWaitingThreadSet.contains(queuedThread)) {
                            if (log.isDebugEnabled()) {
                                log.debug("interrupt thread '" + queuedThread + "'.");
                            }
                            synchronized (waitingThreadList) {
                                // ?waitingThreadList.remove?A?XbhfinallyO?A?s?
                                // ?XbhremoveO?AXbh?f?s\??A
                                // f??Xbh??A
                                // remove?B
                                waitingThreadList.remove(queuedThread);
                                queuedThread.interrupt();

                                // ??A
                                // Xbh?bNL?[?o^CO?A
                                // Xbh?A???getQueueLength()?s?A
                                // getQueueLength()?AwaitingThreadList??A
                                // waitingThreadList.subLists(ListsubLists)?A
                                // (synchronized (lock))?AXbh?bNL?[?o?B
                                while (getQueuedThreads().contains(queuedThread)) {
                                    Thread.yield();
                                }
                            }
                        }
                    }
                }
            }
        }

        try {
            synchronized (waitingThreadList) {
                waitingThreadList.add(Thread.currentThread());
            }
            super.lockInterruptibly();
            successToLock = true;
        } finally {
            // O??A
            // NX?(?s)???s??
            // NX?(/?s)???I
            // ???sKv?A
            // locktB?[h?bN?B
            synchronized (lock) {
                synchronized (waitingThreadList) {
                    waitingThreadList.remove(Thread.currentThread()); // O?remove?Aremove
                    if (!successToLock) {
                        // O?NX????A
                        // ?Xe?[^Xc?A
                        // ?Xe?[^XNA?B
                        // ?bN??AreturnO????A
                        // ?Xe?[^XNAreturn?B
                        Thread.interrupted();
                    }
                }
            }
        }
    }

    /**
     * ?bN?B
     * <p>
     * ?Xbh?bNz_???AX?[p?[NX?\bh?A?bN?B<br>
     * </p>
     * <p>
     * NXg|Cg?B<br>
     * ?E?bNz_Xbh?\bh?s?AOX??[?B(A)<br>
     * </p>
     * @see java.util.concurrent.locks.ReentrantLock#unlock()
     */
    @Override
    public void unlock() {
        if (getOwner() != Thread.currentThread()) {
            return;
        }
        synchronized (lock) {
            super.unlock();

            // ?bNXbh?bN(?u)?A
            // Xbh?AXbhf/?s?ssynchronizedu?bN??A
            // synchronizedu?bN?B
            while (getQueueLength() > 0 && getOwner() == null) {
                Thread.yield();
            }
        }
    }

    /**
     * fVACY??(g)?B
     * <p>
     * fVACY?ARXgN^??l??AVACY/fVACYs\tB?[h??\z?B<br>
     * ?AX?[p?[NXSerializable?AVACY/fVACYgp???B
     * </p>
     * @param stream ObjectInputStream
     * @throws java.io.IOException
     * @throws ClassNotFoundException
     * @see ObjectInputStream
     */
    private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException {
        stream.defaultReadObject();
        lock = new Object();
        waitingThreadList = new LinkedList<Thread>();
    }
}