Java tutorial
/* * 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>(); } }