-
Notifications
You must be signed in to change notification settings - Fork 0
/
BaseThread.java
205 lines (179 loc) · 4.33 KB
/
BaseThread.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package common;
import java.util.Random;
/**
* Class BaseThread
* Simply one customized base class for many of our own threads.
*
* An attempt to maintain an automatic unique TID (thread ID)
* among all the derivatives and allow setting your own if needed.
* Plus some methods for the sync exercises.
*
* $Revision: 1.2 $
* $Last Revision Date: 2021/03/22 $
*
* @author Serguei A. Mokhov, [email protected]
*/
public class BaseThread extends Thread
{
/*
* ------------
* Data members
* ------------
*/
/**
* Preserves value across all instances
*/
public static int siNextTID = 1;
/**
* Our Thread ID
*/
protected int iTID;
/**
* TID of a thread to proceed to the phase II
*/
private static int siTurn = 1;
/*
* ------------
* Constructors
* ------------
*/
/**
* Default
*/
public BaseThread()
{
setTID();
}
/**
* Assigns name to the thread and places it to the specified group
*
* @param poGroup ThreadGroup to add this thread to
* @param pstrName A string indicating human-readable thread's name
*/
public BaseThread(ThreadGroup poGroup, String pstrName)
{
super(poGroup, pstrName);
setTID();
}
/**
* Sets user-specified TID
*/
public BaseThread(final int piTID)
{
this.iTID = piTID;
}
/**
* Retrieves our TID
* @return TID, integer
*/
public final int getTID()
{
return this.iTID;
}
/**
* Sets internal TID and updates next TID on contruction time, so it's private.
*/
private final void setTID()
{
this.iTID = siNextTID++;
}
/**
* Just a make up for the PHASE I to make it somewhat tangeable.
* Must be atomic.
*/
protected synchronized void phase1()
{
System.out.println(this.getClass().getName() + " thread [TID=" + this.iTID + "] starts PHASE I.");
System.out.println
(
"Some stats info in the PHASE I:\n" +
" iTID = " + this.iTID +
", siNextTID = " + siNextTID +
", siTurn = " + siTurn +
".\n Their \"checksum\": " + (siNextTID * 100 + this.iTID * 10 + siTurn)
);
System.out.println(this.getClass().getName() + " thread [TID=" + this.iTID + "] finishes PHASE I.");
}
/**
* Just a make up for the PHASE II to make it somewhat tangeable.
* Must be atomic.
*/
protected synchronized void phase2()
{
System.out.println(this.getClass().getName() + " thread [TID=" + this.iTID + "] starts PHASE II.");
System.out.println
(
"Some stats info in the PHASE II:\n" +
" iTID = " + this.iTID +
", siNextTID = " + siNextTID +
", siTurn = " + siTurn +
".\n Their \"checksum\": " + (siNextTID * 100 + this.iTID * 10 + siTurn)
);
System.out.println(this.getClass().getName() + " thread [TID=" + this.iTID + "] finishes PHASE II.");
}
/**
* Test-and-Set for the iTurn variable.
*
* Use to proceed to the phase II in the correct order.
* Must be atomic.
*
* @param pcIncreasingOrder true if TIDs are in increasing order; false otherwise
*
* @return Returns true if if the TID of currently running thread matches the turn, 'false' otherwise
*/
public synchronized boolean turnTestAndSet(boolean pcIncreasingOrder)
{
// test
if(siTurn == this.iTID)
{
// set siTurn = siTurn +/- 1;
if(pcIncreasingOrder == true)
siTurn++;
else
siTurn--;
return true;
}
return false;
}
/**
* Always assumes the increasing order
*/
public synchronized boolean turnTestAndSet()
{
return turnTestAndSet(true);
}
/**
* Allows setting arbitratu turn value. Should be set only before
* the threads are started
*/
public static void setInitialTurn(int piTurn)
{
siTurn = piTurn;
}
/**
* Default ascending order
*/
public static void setInitialTurnAscending()
{
setInitialTurn(1);
}
/**
* Descending order
*/
public static void setInitialTurnDescending()
{
setInitialTurn(siNextTID - 1);
}
/**
* Calls yield() several (4-40, pseudorandomly) times.
* Next to useless, but helps to mix up the execution of phases.
* Must NOT be atomic.
*/
public void randomYield()
{
// Generate from 5 to 40 yield()'s pseudorandomly
int iNumYields = (int)((new Random()).nextFloat() * 35) + 5;
for(int i = 0; i < iNumYields; i++)
Thread.yield();
}
}