8056152: API to create Threads that do not inherit inheritable thread-local initial values
Reviewed-by: alanb, dholmes, mchung, mr, rriggs
This commit is contained in:
parent
d36b231c45
commit
355dac1a4c
@ -40,6 +40,11 @@ import java.lang.ref.*;
|
||||
* maintained in the variable (e.g., User ID, Transaction ID) must be
|
||||
* automatically transmitted to any child threads that are created.
|
||||
*
|
||||
* <p>Note: During the creation of a new {@link
|
||||
* Thread#Thread(ThreadGroup,Runnable,String,long,boolean) thread}, it is
|
||||
* possible to <i>opt out</i> of receiving initial values for inheritable
|
||||
* thread-local variables.
|
||||
*
|
||||
* @author Josh Bloch and Doug Lea
|
||||
* @see ThreadLocal
|
||||
* @since 1.2
|
||||
|
@ -344,11 +344,11 @@ class Thread implements Runnable {
|
||||
|
||||
/**
|
||||
* Initializes a Thread with the current AccessControlContext.
|
||||
* @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
|
||||
* @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)
|
||||
*/
|
||||
private void init(ThreadGroup g, Runnable target, String name,
|
||||
long stackSize) {
|
||||
init(g, target, name, stackSize, null);
|
||||
init(g, target, name, stackSize, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,9 +361,12 @@ class Thread implements Runnable {
|
||||
* zero to indicate that this parameter is to be ignored.
|
||||
* @param acc the AccessControlContext to inherit, or
|
||||
* AccessController.getContext() if null
|
||||
* @param inheritThreadLocals if {@code true}, inherit initial values for
|
||||
* inheritable thread-locals from the constructing thread
|
||||
*/
|
||||
private void init(ThreadGroup g, Runnable target, String name,
|
||||
long stackSize, AccessControlContext acc) {
|
||||
long stackSize, AccessControlContext acc,
|
||||
boolean inheritThreadLocals) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name cannot be null");
|
||||
}
|
||||
@ -414,7 +417,7 @@ class Thread implements Runnable {
|
||||
acc != null ? acc : AccessController.getContext();
|
||||
this.target = target;
|
||||
setPriority(priority);
|
||||
if (parent.inheritableThreadLocals != null)
|
||||
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
|
||||
this.inheritableThreadLocals =
|
||||
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
|
||||
/* Stash the specified stack size in case the VM cares */
|
||||
@ -468,7 +471,7 @@ class Thread implements Runnable {
|
||||
* This is not a public constructor.
|
||||
*/
|
||||
Thread(Runnable target, AccessControlContext acc) {
|
||||
init(null, target, "Thread-" + nextThreadNum(), 0, acc);
|
||||
init(null, target, "Thread-" + nextThreadNum(), 0, acc, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -677,6 +680,62 @@ class Thread implements Runnable {
|
||||
init(group, target, name, stackSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new {@code Thread} object so that it has {@code target}
|
||||
* as its run object, has the specified {@code name} as its name,
|
||||
* belongs to the thread group referred to by {@code group}, has
|
||||
* the specified {@code stackSize}, and inherits initial values for
|
||||
* {@linkplain InheritableThreadLocal inheritable thread-local} variables
|
||||
* if {@code inheritThreadLocals} is {@code true}.
|
||||
*
|
||||
* <p> This constructor is identical to {@link
|
||||
* #Thread(ThreadGroup,Runnable,String,long)} with the added ability to
|
||||
* suppress, or not, the inheriting of initial values for inheritable
|
||||
* thread-local variables from the constructing thread. This allows for
|
||||
* finer grain control over inheritable thread-locals. Care must be taken
|
||||
* when passing a value of {@code false} for {@code inheritThreadLocals},
|
||||
* as it may lead to unexpected behavior if the new thread executes code
|
||||
* that expects a specific thread-local value to be inherited.
|
||||
*
|
||||
* <p> Specifying a value of {@code true} for the {@code inheritThreadLocals}
|
||||
* parameter will cause this constructor to behave exactly like the
|
||||
* {@code Thread(ThreadGroup, Runnable, String, long)} constructor.
|
||||
*
|
||||
* @param group
|
||||
* the thread group. If {@code null} and there is a security
|
||||
* manager, the group is determined by {@linkplain
|
||||
* SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
|
||||
* If there is not a security manager or {@code
|
||||
* SecurityManager.getThreadGroup()} returns {@code null}, the group
|
||||
* is set to the current thread's thread group.
|
||||
*
|
||||
* @param target
|
||||
* the object whose {@code run} method is invoked when this thread
|
||||
* is started. If {@code null}, this thread's run method is invoked.
|
||||
*
|
||||
* @param name
|
||||
* the name of the new thread
|
||||
*
|
||||
* @param stackSize
|
||||
* the desired stack size for the new thread, or zero to indicate
|
||||
* that this parameter is to be ignored
|
||||
*
|
||||
* @param inheritThreadLocals
|
||||
* if {@code true}, inherit initial values for inheritable
|
||||
* thread-locals from the constructing thread, otherwise no initial
|
||||
* values are inherited
|
||||
*
|
||||
* @throws SecurityException
|
||||
* if the current thread cannot create a thread in the specified
|
||||
* thread group
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public Thread(ThreadGroup group, Runnable target, String name,
|
||||
long stackSize, boolean inheritThreadLocals) {
|
||||
init(group, target, name, stackSize, null, inheritThreadLocals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes this thread to begin execution; the Java Virtual Machine
|
||||
* calls the <code>run</code> method of this thread.
|
||||
|
@ -29,7 +29,6 @@ import java.security.PrivilegedAction;
|
||||
import java.security.AccessController;
|
||||
import jdk.internal.misc.JavaLangAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
import sun.misc.VM;
|
||||
|
||||
final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
|
||||
@ -131,7 +130,7 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||
for (ThreadGroup tgn = tg;
|
||||
tgn != null;
|
||||
tg = tgn, tgn = tg.getParent());
|
||||
Thread sft = new ManagedLocalsThread(tg, proc, "Secondary finalizer");
|
||||
Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
|
||||
sft.start();
|
||||
try {
|
||||
sft.join();
|
||||
@ -190,10 +189,10 @@ final class Finalizer extends FinalReference<Object> { /* Package-private; must
|
||||
}}});
|
||||
}
|
||||
|
||||
private static class FinalizerThread extends ManagedLocalsThread {
|
||||
private static class FinalizerThread extends Thread {
|
||||
private volatile boolean running;
|
||||
FinalizerThread(ThreadGroup g) {
|
||||
super(g, "Finalizer");
|
||||
super(g, null, "Finalizer", 0, false);
|
||||
}
|
||||
public void run() {
|
||||
// in case of recursive call to run()
|
||||
|
@ -29,7 +29,6 @@ import sun.misc.Cleaner;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.JavaLangRefAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
/**
|
||||
* Abstract base class for reference objects. This class defines the
|
||||
@ -128,7 +127,7 @@ public abstract class Reference<T> {
|
||||
|
||||
/* High-priority thread to enqueue pending References
|
||||
*/
|
||||
private static class ReferenceHandler extends ManagedLocalsThread {
|
||||
private static class ReferenceHandler extends Thread {
|
||||
|
||||
private static void ensureClassInitialized(Class<?> clazz) {
|
||||
try {
|
||||
@ -147,7 +146,7 @@ public abstract class Reference<T> {
|
||||
}
|
||||
|
||||
ReferenceHandler(ThreadGroup g, String name) {
|
||||
super(g, name);
|
||||
super(g, null, name, 0, false);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
@ -82,7 +82,7 @@ public class GC {
|
||||
*/
|
||||
public static native long maxObjectInspectionAge();
|
||||
|
||||
private static class Daemon extends ManagedLocalsThread {
|
||||
private static class Daemon extends Thread {
|
||||
|
||||
public void run() {
|
||||
for (;;) {
|
||||
@ -122,7 +122,7 @@ public class GC {
|
||||
}
|
||||
|
||||
private Daemon(ThreadGroup tg) {
|
||||
super(tg, "GC Daemon");
|
||||
super(tg, null, "GC Daemon", 0L, false);
|
||||
}
|
||||
|
||||
/* Create a new daemon thread in the root thread group */
|
||||
|
@ -35,8 +35,10 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* A thread that has no permissions, is not a member of any user-defined
|
||||
* ThreadGroup and supports the ability to erase ThreadLocals.
|
||||
*/
|
||||
public final class InnocuousThread extends ManagedLocalsThread {
|
||||
public final class InnocuousThread extends Thread {
|
||||
private static final jdk.internal.misc.Unsafe UNSAFE;
|
||||
private static final long THREAD_LOCALS;
|
||||
private static final long INHERITABLE_THREAD_LOCALS;
|
||||
private static final ThreadGroup INNOCUOUSTHREADGROUP;
|
||||
private static final AccessControlContext ACC;
|
||||
private static final long INHERITEDACCESSCONTROLCONTEXT;
|
||||
@ -54,7 +56,7 @@ public final class InnocuousThread extends ManagedLocalsThread {
|
||||
}
|
||||
|
||||
public InnocuousThread(ThreadGroup group, Runnable target, String name) {
|
||||
super(group, target, name);
|
||||
super(group, target, name, 0L, false);
|
||||
UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC);
|
||||
UNSAFE.putOrderedObject(this, CONTEXTCLASSLOADER, ClassLoader.getSystemClassLoader());
|
||||
}
|
||||
@ -73,6 +75,14 @@ public final class InnocuousThread extends ManagedLocalsThread {
|
||||
throw new SecurityException("setContextClassLoader");
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops all thread locals (and inherited thread locals).
|
||||
*/
|
||||
public final void eraseThreadLocals() {
|
||||
UNSAFE.putObject(this, THREAD_LOCALS, null);
|
||||
UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null);
|
||||
}
|
||||
|
||||
// ensure run method is run only once
|
||||
private volatile boolean hasRun;
|
||||
|
||||
@ -96,6 +106,10 @@ public final class InnocuousThread extends ManagedLocalsThread {
|
||||
Class<?> tk = Thread.class;
|
||||
Class<?> gk = ThreadGroup.class;
|
||||
|
||||
THREAD_LOCALS = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocals"));
|
||||
INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("inheritableThreadLocals"));
|
||||
INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("inheritedAccessControlContext"));
|
||||
CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset
|
||||
|
@ -213,7 +213,7 @@ public final class Signal {
|
||||
}
|
||||
};
|
||||
if (handler != null) {
|
||||
new ManagedLocalsThread(runnable, sig + " handler").start();
|
||||
new Thread(null, runnable, sig + " handler", 0, false).start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ package sun.net;
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.net.ServerSocket;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
/**
|
||||
* This is the base class for network servers. To define a new type
|
||||
@ -73,7 +72,7 @@ public class NetworkServer implements Runnable, Cloneable {
|
||||
NetworkServer n = (NetworkServer)clone();
|
||||
n.serverSocket = null;
|
||||
n.clientSocket = ns;
|
||||
new ManagedLocalsThread(n).start();
|
||||
new Thread(null, n, "NetworkServer", 0, false).start();
|
||||
} catch(Exception e) {
|
||||
System.out.print("Server failure\n");
|
||||
e.printStackTrace();
|
||||
@ -108,7 +107,7 @@ public class NetworkServer implements Runnable, Cloneable {
|
||||
for each new connection. */
|
||||
public final void startServer(int port) throws IOException {
|
||||
serverSocket = new ServerSocket(port, 50);
|
||||
serverInstance = new ManagedLocalsThread(this);
|
||||
serverInstance = new Thread(null, this, "NetworkServer", 0, false);
|
||||
serverInstance.start();
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,8 @@ package sun.net.www;
|
||||
import java.net.URL;
|
||||
import java.io.*;
|
||||
import java.util.StringTokenizer;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
class MimeLauncher extends ManagedLocalsThread {
|
||||
class MimeLauncher extends Thread {
|
||||
java.net.URLConnection uc;
|
||||
MimeEntry m;
|
||||
String genericTempFileTemplate;
|
||||
@ -38,7 +37,7 @@ class MimeLauncher extends ManagedLocalsThread {
|
||||
|
||||
MimeLauncher (MimeEntry M, java.net.URLConnection uc,
|
||||
InputStream is, String tempFileTemplate, String threadName) throws ApplicationLaunchException {
|
||||
super(threadName);
|
||||
super(null, null, threadName, 0, false);
|
||||
m = M;
|
||||
this.uc = uc;
|
||||
this.is = is;
|
||||
|
@ -30,7 +30,6 @@ import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
/**
|
||||
* Base implementation of background poller thread used in watch service
|
||||
@ -60,7 +59,7 @@ abstract class AbstractPoller implements Runnable {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
Thread thr = new ManagedLocalsThread(thisRunnable);
|
||||
Thread thr = new Thread(null, thisRunnable, "FileSystemWatchService", 0, false);
|
||||
thr.setDaemon(true);
|
||||
thr.start();
|
||||
return null;
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@ -118,7 +117,7 @@ abstract class Cancellable implements Runnable {
|
||||
* thread by writing into the memory location that it polls cooperatively.
|
||||
*/
|
||||
static void runInterruptibly(Cancellable task) throws ExecutionException {
|
||||
Thread t = new ManagedLocalsThread(task);
|
||||
Thread t = new Thread(null, task, "NIO-Task", 0, false);
|
||||
t.start();
|
||||
boolean cancelledByInterrupt = false;
|
||||
while (t.isAlive()) {
|
||||
|
@ -35,7 +35,6 @@ import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import com.sun.nio.file.SensitivityWatchEventModifier;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
/**
|
||||
* Simple WatchService implementation that uses periodic tasks to poll
|
||||
@ -59,7 +58,7 @@ class PollingWatchService
|
||||
.newSingleThreadScheduledExecutor(new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new ManagedLocalsThread(r);
|
||||
Thread t = new Thread(null, r, "FileSystemWatchService", 0, false);
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}});
|
||||
|
@ -75,7 +75,6 @@ import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Random;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
abstract class SeedGenerator {
|
||||
@ -305,9 +304,11 @@ abstract class SeedGenerator {
|
||||
}
|
||||
finalsg[0] = new ThreadGroup
|
||||
(group, "SeedGenerator ThreadGroup");
|
||||
Thread newT = new ManagedLocalsThread(finalsg[0],
|
||||
Thread newT = new Thread(finalsg[0],
|
||||
ThreadedSeedGenerator.this,
|
||||
"SeedGenerator Thread");
|
||||
"SeedGenerator Thread",
|
||||
0,
|
||||
false);
|
||||
newT.setPriority(Thread.MIN_PRIORITY);
|
||||
newT.setDaemon(true);
|
||||
return newT;
|
||||
@ -342,8 +343,8 @@ abstract class SeedGenerator {
|
||||
// Start some noisy threads
|
||||
try {
|
||||
BogusThread bt = new BogusThread();
|
||||
Thread t = new ManagedLocalsThread
|
||||
(seedGroup, bt, "SeedGenerator Thread");
|
||||
Thread t = new Thread
|
||||
(seedGroup, bt, "SeedGenerator Thread", 0, false);
|
||||
t.start();
|
||||
} catch (Exception e) {
|
||||
throw new InternalError("internal error: " +
|
||||
|
@ -40,7 +40,6 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.net.ssl.*;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
import jdk.internal.misc.JavaNetInetAddressAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
@ -1153,10 +1152,13 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
HandshakeCompletedEvent event =
|
||||
new HandshakeCompletedEvent(this, sess);
|
||||
|
||||
Thread thread = new ManagedLocalsThread(
|
||||
Thread thread = new Thread(
|
||||
null,
|
||||
new NotifyHandshake(
|
||||
handshakeListeners.entrySet(), event),
|
||||
"HandshakeCompletedNotify-Thread");
|
||||
"HandshakeCompletedNotify-Thread",
|
||||
0,
|
||||
false);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
|
||||
/**
|
||||
* A multi-threaded implementation of Selector for Windows.
|
||||
@ -404,13 +403,14 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
||||
}
|
||||
|
||||
// Represents a helper thread used for select.
|
||||
private final class SelectThread extends ManagedLocalsThread {
|
||||
private final class SelectThread extends Thread {
|
||||
private final int index; // index of this thread
|
||||
final SubSelector subSelector;
|
||||
private long lastRun = 0; // last run number
|
||||
private volatile boolean zombie;
|
||||
// Creates a new thread
|
||||
private SelectThread(int i) {
|
||||
super(null, null, "SelectorHelper", 0, false);
|
||||
this.index = i;
|
||||
this.subSelector = new SubSelector(i);
|
||||
//make sure we wait for next round of poll
|
||||
|
100
jdk/test/java/lang/Thread/ITLConstructor.java
Normal file
100
jdk/test/java/lang/Thread/ITLConstructor.java
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Basic test for Thread(ThreadGroup,Runnable,String,long,boolean)
|
||||
*/
|
||||
|
||||
public class ITLConstructor {
|
||||
static InheritableThreadLocal<Integer> n = new InheritableThreadLocal<>() {
|
||||
protected Integer initialValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected Integer childValue(Integer parentValue) {
|
||||
return parentValue + 1;
|
||||
}
|
||||
};
|
||||
|
||||
static final int CHILD_THREAD_COUNT = 10;
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
test(true);
|
||||
test(false);
|
||||
}
|
||||
|
||||
static void test(boolean inherit) throws Exception {
|
||||
// concurrent access to separate indexes is ok
|
||||
int[] x = new int[CHILD_THREAD_COUNT];
|
||||
Thread child = new Thread(Thread.currentThread().getThreadGroup(),
|
||||
new AnotherRunnable(0, x, inherit),
|
||||
"ITLConstructor-thread-"+(0),
|
||||
0,
|
||||
inherit);
|
||||
child.start();
|
||||
child.join(); // waits for *all* threads to complete
|
||||
|
||||
// Check results
|
||||
for(int i=0; i<CHILD_THREAD_COUNT; i++) {
|
||||
int expectedValue = 1;
|
||||
if (inherit)
|
||||
expectedValue = i+1;
|
||||
|
||||
if (x[i] != expectedValue)
|
||||
throw (new Exception("Got x[" + i + "] = " + x[i]
|
||||
+ ", expected: " + expectedValue));
|
||||
}
|
||||
}
|
||||
|
||||
static class AnotherRunnable implements Runnable {
|
||||
final int threadId;
|
||||
final int[] x;
|
||||
final boolean inherit;
|
||||
AnotherRunnable(int threadId, int[] x, boolean inherit) {
|
||||
this.threadId = threadId;
|
||||
this.x = x;
|
||||
this.inherit = inherit;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
int itlValue = n.get();
|
||||
|
||||
if (threadId < CHILD_THREAD_COUNT-1) {
|
||||
Thread child = new Thread(Thread.currentThread().getThreadGroup(),
|
||||
new AnotherRunnable(threadId+1, x, inherit),
|
||||
"ITLConstructor-thread-" + (threadId+1),
|
||||
0,
|
||||
inherit);
|
||||
child.start();
|
||||
try {
|
||||
child.join();
|
||||
} catch(InterruptedException e) {
|
||||
throw(new RuntimeException("Interrupted", e));
|
||||
}
|
||||
}
|
||||
|
||||
x[threadId] = itlValue+1;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user