%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.jelly.tags.threads.Mutex |
|
|
1 | /* |
|
2 | * Copyright 2002-2004 The Apache Software Foundation |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | /* |
|
17 | File: Mutex.java |
|
18 | ||
19 | Originally written by Doug Lea and released into the public domain. |
|
20 | This may be used for any purposes whatsoever without acknowledgment. |
|
21 | Thanks for the assistance and support of Sun Microsystems Labs, |
|
22 | and everyone contributing, testing, and using this code. |
|
23 | ||
24 | History: |
|
25 | Date Who What |
|
26 | 11Jun1998 dl Create public version |
|
27 | */ |
|
28 | ||
29 | package org.apache.commons.jelly.tags.threads; |
|
30 | ||
31 | /** |
|
32 | * A simple non-reentrant mutual exclusion lock. |
|
33 | * The lock is free upon construction. Each acquire gets the |
|
34 | * lock, and each release frees it. Releasing a lock that |
|
35 | * is already free has no effect. |
|
36 | * <p> |
|
37 | * This implementation makes no attempt to provide any fairness |
|
38 | * or ordering guarantees. If you need them, consider using one of |
|
39 | * the Semaphore implementations as a locking mechanism. |
|
40 | * <p> |
|
41 | * <b>Sample usage</b><br> |
|
42 | * <p> |
|
43 | * Mutex can be useful in constructions that cannot be |
|
44 | * expressed using java synchronized blocks because the |
|
45 | * acquire/release pairs do not occur in the same method or |
|
46 | * code block. For example, you can use them for hand-over-hand |
|
47 | * locking across the nodes of a linked list. This allows |
|
48 | * extremely fine-grained locking, and so increases |
|
49 | * potential concurrency, at the cost of additional complexity and |
|
50 | * overhead that would normally make this worthwhile only in cases of |
|
51 | * extreme contention. |
|
52 | * <pre> |
|
53 | * class Node { |
|
54 | * Object item; |
|
55 | * Node next; |
|
56 | * Mutex lock = new Mutex(); // each node keeps its own lock |
|
57 | * |
|
58 | * Node(Object x, Node n) { item = x; next = n; } |
|
59 | * } |
|
60 | * |
|
61 | * class List { |
|
62 | * protected Node head; // pointer to first node of list |
|
63 | * |
|
64 | * // Use plain java synchronization to protect head field. |
|
65 | * // (We could instead use a Mutex here too but there is no |
|
66 | * // reason to do so.) |
|
67 | * protected synchronized Node getHead() { return head; } |
|
68 | * |
|
69 | * boolean search(Object x) throws InterruptedException { |
|
70 | * Node p = getHead(); |
|
71 | * if (p == null) return false; |
|
72 | * |
|
73 | * // (This could be made more compact, but for clarity of illustration, |
|
74 | * // all of the cases that can arise are handled separately.) |
|
75 | * |
|
76 | * p.lock.acquire(); // Prime loop by acquiring first lock. |
|
77 | * // (If the acquire fails due to |
|
78 | * // interrupt, the method will throw |
|
79 | * // InterruptedException now, |
|
80 | * // so there is no need for any |
|
81 | * // further cleanup.) |
|
82 | * for (;;) { |
|
83 | * if (x.equals(p.item)) { |
|
84 | * p.lock.release(); // release current before return |
|
85 | * return true; |
|
86 | * } |
|
87 | * else { |
|
88 | * Node nextp = p.next; |
|
89 | * if (nextp == null) { |
|
90 | * p.lock.release(); // release final lock that was held |
|
91 | * return false; |
|
92 | * } |
|
93 | * else { |
|
94 | * try { |
|
95 | * nextp.lock.acquire(); // get next lock before releasing current |
|
96 | * } |
|
97 | * catch (InterruptedException ex) { |
|
98 | * p.lock.release(); // also release current if acquire fails |
|
99 | * throw ex; |
|
100 | * } |
|
101 | * p.lock.release(); // release old lock now that new one held |
|
102 | * p = nextp; |
|
103 | * } |
|
104 | * } |
|
105 | * } |
|
106 | * } |
|
107 | * |
|
108 | * synchronized void add(Object x) { // simple prepend |
|
109 | * // The use of `synchronized' here protects only head field. |
|
110 | * // The method does not need to wait out other traversers |
|
111 | * // who have already made it past head. |
|
112 | * |
|
113 | * head = new Node(x, head); |
|
114 | * } |
|
115 | * |
|
116 | * // ... other similar traversal and update methods ... |
|
117 | * } |
|
118 | * </pre> |
|
119 | * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] |
|
120 | * |
|
121 | * -------------------------------------------------------------------------------------------- |
|
122 | * This Mutex is used to add the still running lock to the JellyThread tag. |
|
123 | **/ |
|
124 | ||
125 | 152 | public class Mutex { |
126 | ||
127 | /** The lock status **/ |
|
128 | 76 | protected boolean inuse_ = false; |
129 | ||
130 | public void acquire() throws InterruptedException { |
|
131 | 92 | if (Thread.interrupted()) throw new InterruptedException(); |
132 | 92 | synchronized (this) { |
133 | try { |
|
134 | 92 | while (inuse_) wait(); |
135 | 90 | inuse_ = true; |
136 | 90 | } catch (InterruptedException ex) { |
137 | 0 | notify(); |
138 | 0 | throw ex; |
139 | } |
|
140 | 90 | } |
141 | 90 | } |
142 | ||
143 | public synchronized void release() { |
|
144 | 48 | inuse_ = false; |
145 | 48 | notify(); |
146 | 48 | } |
147 | ||
148 | ||
149 | public boolean attempt(long msecs) throws InterruptedException { |
|
150 | 2 | if (Thread.interrupted()) throw new InterruptedException(); |
151 | 2 | synchronized (this) { |
152 | 2 | if (!inuse_) { |
153 | 0 | inuse_ = true; |
154 | 0 | return true; |
155 | 2 | } else if (msecs <= 0) |
156 | 0 | return false; |
157 | else { |
|
158 | 2 | long waitTime = msecs; |
159 | 2 | long start = System.currentTimeMillis(); |
160 | try { |
|
161 | 2 | for (; ;) { |
162 | 2 | wait(waitTime); |
163 | 2 | if (!inuse_) { |
164 | 0 | inuse_ = true; |
165 | 0 | return true; |
166 | } else { |
|
167 | 2 | waitTime = msecs - (System.currentTimeMillis() - start); |
168 | 2 | if (waitTime <= 0) |
169 | 2 | return false; |
170 | } |
|
171 | } |
|
172 | } catch (InterruptedException ex) { |
|
173 | 0 | notify(); |
174 | 0 | throw ex; |
175 | } |
|
176 | } |
|
177 | 0 | } |
178 | } |
|
179 | ||
180 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |