Skip to content

Commit 68b6673

Browse files
committed
Version 1.5.2 - Added Windows support and Javadoc for all public methods.
1 parent 072b74b commit 68b6673

File tree

7 files changed

+107
-6
lines changed

7 files changed

+107
-6
lines changed

README

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ https://www.ohloh.net/p/Java-Thread-Affinity
44

55
[ Version History ]
66

7+
Version 1.5.2 - Added Windows support and Javadoc for all public methods.
8+
79
Version 1.5.1 - Add changes to support i386 and Intel i3
810
https://github.com/peter-lawrey/Java-Thread-Affinity/issues/9
911
https://github.com/peter-lawrey/Java-Thread-Affinity/issues/10

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
<groupId>vanilla.java</groupId>
2424
<artifactId>affinity</artifactId>
25-
<version>1.5.1</version>
25+
<version>1.5.2</version>
2626
<packaging>jar</packaging>
2727

2828
<licenses>

src/main/java/vanilla/java/affinity/AffinityLock.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import java.util.logging.Logger;
2828

2929
/**
30+
* This utility class support locking a thread to a single core, or reserving a whole core for a thread.
31+
*
3032
* @author peter.lawrey
3133
*/
3234
public class AffinityLock {
@@ -61,6 +63,14 @@ public class AffinityLock {
6163
}
6264
}
6365

66+
/**
67+
* Set the CPU layout for this machine. CPUs which are not mentioned will be ignored.
68+
* <p/>
69+
* Changing the layout will have no impact on thread which have already been assigned.
70+
* It only affects subsequent assignments.
71+
*
72+
* @param cpuLayout for this application to use for this machine.
73+
*/
6474
public static void cpuLayout(CpuLayout cpuLayout) {
6575
synchronized (AffinityLock.class) {
6676
AffinityLock.cpuLayout = cpuLayout;
@@ -84,6 +94,9 @@ private static int coreForId(int id) {
8494
return cpuLayout.socketId(id) * cpuLayout.coresPerSocket() + cpuLayout.coreId(id);
8595
}
8696

97+
/**
98+
* @return The current CpuLayout for the application.
99+
*/
87100
public static CpuLayout cpuLayout() {
88101
return cpuLayout;
89102
}
@@ -95,18 +108,46 @@ private static long getReservedAffinity0() {
95108
return Long.parseLong(reservedAffinity, 16);
96109
}
97110

111+
/**
112+
* Assign any free cpu to this thread.
113+
*
114+
* @return A handle for the current AffinityLock.
115+
*/
98116
public static AffinityLock acquireLock() {
99117
return acquireLock(true);
100118
}
101119

120+
/**
121+
* Assign any free core to this thread.
122+
* <p/>
123+
* In reality, only one cpu is assigned, the rest of the threads for that core are reserved so they are not used.
124+
*
125+
* @return A handle for the current AffinityLock.
126+
*/
102127
public static AffinityLock acquireCore() {
103128
return acquireCore(true);
104129
}
105130

131+
/**
132+
* Assign a cpu which can be bound to the current thread or another thread.
133+
* <p/>
134+
* This can be used for defining your thread layout centrally and passing the handle via dependency injection.
135+
*
136+
* @param bind if true, bind the current thread, if false, reserve a cpu which can be bound later.
137+
* @return A handle for an affinity lock.
138+
*/
106139
public static AffinityLock acquireLock(boolean bind) {
107140
return acquireLock(bind, -1, AffinityStrategies.ANY);
108141
}
109142

143+
/**
144+
* Assign a core(and all its cpus) which can be bound to the current thread or another thread.
145+
* <p/>
146+
* This can be used for defining your thread layout centrally and passing the handle via dependency injection.
147+
*
148+
* @param bind if true, bind the current thread, if false, reserve a cpu which can be bound later.
149+
* @return A handle for an affinity lock.
150+
*/
110151
public static AffinityLock acquireCore(boolean bind) {
111152
return acquireCore(bind, -1, AffinityStrategies.ANY);
112153
}
@@ -152,6 +193,9 @@ private static AffinityLock acquireCore(boolean bind, int cpuId, AffinityStrateg
152193
}
153194

154195

196+
/**
197+
* @return All the current locks as a String.
198+
*/
155199
public static String dumpLocks() {
156200
return dumpLocks0(LOCKS);
157201
}
@@ -193,10 +237,18 @@ private void assignCurrentThread(boolean bind, boolean wholeCore) {
193237
bind(wholeCore);
194238
}
195239

240+
/**
241+
* Bind the current thread to this reserved lock.
242+
*/
196243
public void bind() {
197244
bind(false);
198245
}
199246

247+
/**
248+
* Bind the current thread to this reserved lock.
249+
*
250+
* @param wholeCore if true, also reserve the whole core.
251+
*/
200252
public void bind(boolean wholeCore) {
201253
if (bound && assignedThread != null && assignedThread.isAlive())
202254
throw new IllegalStateException("cpu " + id + " already bound to " + assignedThread);
@@ -239,10 +291,19 @@ private boolean canReserve() {
239291
return true;
240292
}
241293

294+
/**
295+
* Give another affinity lock relative to this one based on a list of strategies.
296+
*
297+
* @param strategies To dertemine if you want the same/different core/socket.
298+
* @return A matching AffinityLock.
299+
*/
242300
public AffinityLock acquireLock(AffinityStrategy... strategies) {
243301
return acquireLock(false, id, strategies);
244302
}
245303

304+
/**
305+
* Release the current AffinityLock which can be discarded.
306+
*/
246307
public void release() {
247308
Thread t = Thread.currentThread();
248309
synchronized (AffinityLock.class) {
@@ -262,4 +323,13 @@ public void release() {
262323
}
263324
AffinitySupport.setAffinity(BASE_AFFINITY);
264325
}
326+
327+
@Override
328+
protected void finalize() throws Throwable {
329+
if (reserved) {
330+
LOGGER.warning("Affinity lock for " + assignedThread + " was discarded rather than release()d in a controlled manner.");
331+
release();
332+
}
333+
super.finalize();
334+
}
265335
}

src/main/java/vanilla/java/affinity/AffinityStrategies.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,56 @@
1717
package vanilla.java.affinity;
1818

1919
/**
20+
* Pre-defined strategies for determining which thread to pick next.
21+
*
2022
* @author peter.lawrey
2123
*/
2224
public enum AffinityStrategies implements AffinityStrategy {
25+
/**
26+
* Any free cpu.
27+
*/
2328
ANY {
2429
@Override
2530
public boolean matches(int cpuId, int cpuId2) {
2631
return true;
2732
}
28-
}, SAME_CORE {
33+
},
34+
/**
35+
* Must be a cpu on the same core.
36+
*/
37+
SAME_CORE {
2938
@Override
3039
public boolean matches(int cpuId, int cpuId2) {
3140
CpuLayout cpuLayout = AffinityLock.cpuLayout();
3241
return cpuLayout.socketId(cpuId) == cpuLayout.socketId(cpuId2) &&
3342
cpuLayout.coreId(cpuId) == cpuLayout.coreId(cpuId2);
3443
}
35-
}, SAME_SOCKET {
44+
},
45+
/**
46+
* Must be a cpu on the same socket/chip.
47+
*/
48+
SAME_SOCKET {
3649
@Override
3750
public boolean matches(int cpuId, int cpuId2) {
3851
CpuLayout cpuLayout = AffinityLock.cpuLayout();
3952
return cpuLayout.socketId(cpuId) == cpuLayout.socketId(cpuId2);
4053
}
41-
}, DIFFERENT_CORE {
54+
},
55+
/**
56+
* Must be a cpu on any other core (or socket)
57+
*/
58+
DIFFERENT_CORE {
4259
@Override
4360
public boolean matches(int cpuId, int cpuId2) {
4461
CpuLayout cpuLayout = AffinityLock.cpuLayout();
4562
return cpuLayout.socketId(cpuId) != cpuLayout.socketId(cpuId2) ||
4663
cpuLayout.coreId(cpuId) != cpuLayout.coreId(cpuId2);
4764
}
48-
}, DIFFERENT_SOCKET {
65+
},
66+
/**
67+
* Must be a cpu on any other socket.
68+
*/
69+
DIFFERENT_SOCKET {
4970
@Override
5071
public boolean matches(int cpuId, int cpuId2) {
5172
CpuLayout cpuLayout = AffinityLock.cpuLayout();

src/main/java/vanilla/java/affinity/AffinityStrategy.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package vanilla.java.affinity;
1818

1919
/**
20+
* Allow you define a strategy for find the a cpu relative to another select cpu.
21+
*
2022
* @author peter.lawrey
2123
*/
2224
public interface AffinityStrategy {

src/main/java/vanilla/java/affinity/AffinitySupport.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.logging.Logger;
2626

2727
/**
28+
* Library to wrap low level JNI or JNA calls. Can be called without needing to know the actual implementation used.
29+
*
2830
* @author peter.lawrey
2931
*/
3032
public enum AffinitySupport {

src/main/java/vanilla/java/affinity/AffinityThreadFactory.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import java.util.concurrent.ThreadFactory;
2020

2121
/**
22+
* This is a ThreadFactory which assigns threads based the strategies provided.
23+
* <p/>
24+
* If no strategies are provided AffinityStrategies.ANY is used.
25+
*
2226
* @author peter.lawrey
2327
*/
2428
public class AffinityThreadFactory implements ThreadFactory {
@@ -35,7 +39,7 @@ public AffinityThreadFactory(String name, AffinityStrategy... strategies) {
3539
public AffinityThreadFactory(String name, boolean daemon, AffinityStrategy... strategies) {
3640
this.name = name;
3741
this.daemon = daemon;
38-
this.strategies = strategies;
42+
this.strategies = strategies.length == 0 ? new AffinityStrategy[]{AffinityStrategies.ANY} : strategies;
3943
}
4044

4145
@Override

0 commit comments

Comments
 (0)