View Javadoc
1   package io.jawk.jrt;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * Jawk
6    * ჻჻჻჻჻჻
7    * Copyright (C) 2006 - 2026 MetricsHub
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23   */
24  
25  import java.util.LinkedList;
26  import java.util.List;
27  
28  /**
29   * Manages multiple blocking code segments simultaneously such that
30   * unblocking one block condition releases the block of all other
31   * block code segments.
32   *
33   * @see BlockObject
34   * @author Danny Daglas
35   */
36  public class BlockManager {
37  
38  	private final Object lock = new Object();
39  
40  	private String notifier = null;
41  
42  	/**
43  	 * Executes all block segments simultaneously, waiting for
44  	 * one block release.
45  	 * <p>
46  	 * The algorithm is as follows:
47  	 * <ul>
48  	 * <li>Collect linked block objects into a List.
49  	 * <li>Spawn a BlockThread for each block object.
50  	 * <li>Wait for notification from any of the BlockThreads.
51  	 * <li>Interrupt remaining block threads.
52  	 * <li>Wait for each BlockThread to die.
53  	 * <li>Return the block object notifier which satisfied their block condition.
54  	 * </ul>
55  	 * <p>
56  	 * And, the BlockThread algorithm is as follows:
57  	 * <ul>
58  	 * <li>try, catch for InterruptedException ...
59  	 * <ul>
60  	 * <li>Execute the BlockObject block segment.
61  	 * <li>Assign the notifier from this BlockObject
62  	 * if one isn't already assigned (to mitigate
63  	 * a race condition).
64  	 * <li>Notify the BlockManager.
65  	 * </ul>
66  	 * <li>If interrupted, do nothing and return.
67  	 * </ul>
68  	 *
69  	 * @param bo BlockObject to employ. Other block objects
70  	 *        may be linked to this block object. In this event,
71  	 *        employ all block objects simultaneously.
72  	 * @return a {@link java.lang.String} object
73  	 */
74  	public String block(BlockObject bo) {
75  		// get all block objects
76  		List<BlockObject> bos = bo.getBlockObjects();
77  		// each block object contains a wait statement
78  		// (either indefinite or timed)
79  
80  		// for each block object
81  		// spawn a thread (preferably using a threadpool)
82  		// do the wait
83  		// signal a break in the block
84  		// interrupt all other threads, resulting in InterruptedExceptions
85  
86  		List<Thread> threadList = new LinkedList<Thread>();
87  		String blockNotifier = null;
88  		synchronized (lock) {
89  			notifier = null;
90  			for (BlockObject blockobj : bos) {
91  				// spawn a thread
92  				Thread t = new BlockThread(blockobj);
93  				t.start();
94  				threadList.add(t);
95  			}
96  
97  			// now, wait for notification from one of the BlockThreads
98  			while (notifier == null) {
99  				try {
100 					lock.wait();
101 				} catch (InterruptedException ie) {
102 					Thread.currentThread().interrupt();
103 				}
104 			}
105 			blockNotifier = notifier;
106 		}
107 
108 		// block successful, interrupt other blockers
109 		// and wait for thread deaths
110 		for (Thread t : threadList) {
111 			t.interrupt();
112 			try {
113 				t.join();
114 			} catch (InterruptedException ie) {
115 				Thread.currentThread().interrupt();
116 			}
117 		}
118 
119 		// return who was the notifier
120 		return blockNotifier;
121 	}
122 
123 	private void notifyUnblock(String notifierTag) {
124 		synchronized (lock) {
125 			if (notifier == null) {
126 				notifier = notifierTag;
127 			}
128 			lock.notifyAll();
129 		}
130 	}
131 
132 	private final class BlockThread extends Thread {
133 
134 		private BlockObject bo;
135 
136 		private BlockThread(BlockObject bo) {
137 			setName("BlockThread for " + bo.getNotifierTag());
138 			this.bo = bo;
139 		}
140 
141 		@Override
142 		public void run() {
143 			try {
144 				bo.block();
145 				notifyUnblock(bo.getNotifierTag());
146 			} catch (InterruptedException ie) {
147 				currentThread().interrupt();
148 			} catch (RuntimeException re) {
149 				throw re;
150 			}
151 		}
152 	}
153 }