< prev index next >

src/java.base/share/classes/java/lang/Thread.java

Print this page

        

@@ -36,10 +36,11 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.LockSupport;
 
+import jdk.internal.misc.Strands;
 import jdk.internal.misc.TerminatingThreadLocal;
 import sun.nio.ch.Interruptible;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import sun.security.util.SecurityConstants;

@@ -196,10 +197,15 @@
     /*
      * Thread ID
      */
     private final long tid;
 
+    /*
+     * Current inner-most continuation
+     */
+    private Continuation cont;
+
     /* For generating thread ID */
     private static long threadSeqNumber;
 
     private static synchronized long nextThreadID() {
         return ++threadSeqNumber;

@@ -233,10 +239,22 @@
         synchronized (me.blockerLock) {
             me.blocker = b;
         }
     }
 
+    Object blockerLock() {
+        return blockerLock;
+    }
+
+    void runInterrupter() {
+        assert Thread.holdsLock(blockerLock);
+        Interruptible b = blocker;
+        if (b != null) {
+            b.interrupt(this);
+        }
+    }
+
     /**
      * The minimum priority that a thread can have.
      */
     public static final int MIN_PRIORITY = 1;
 

@@ -249,16 +267,69 @@
      * The maximum priority that a thread can have.
      */
     public static final int MAX_PRIORITY = 10;
 
     /**
-     * Returns a reference to the currently executing thread object.
+     * Returns the Thread object for the current thread.
      *
-     * @return  the currently executing thread.
+     * <p> When executed in the context of a fiber, the returned Thread object
+     * does not support all features of Thread. In particular, the Thread
+     * is not an <i>active thread</i> in its thread group and so is not enumerated
+     * or acted on by thread group operations. In addition it does not support
+     * the stop, suspend or resume methods.
+     *
+     * @return  the current thread
+     */
+    public static Thread currentThread() {
+        Thread t = currentThread0();
+        Fiber<?> fiber = t.fiber;
+        if (fiber != null) {
+            return fiber.shadowThread();
+        } else {
+            return t;
+        }
+    }
+
+    /**
+     * Returns the current carrier thread.
      */
+    static Thread currentCarrierThread() {
+        return currentThread0();
+    }
+
     @HotSpotIntrinsicCandidate
-    public static native Thread currentThread();
+    private static native Thread currentThread0();
+
+    private Fiber<?> fiber;
+    private FiberScope scope;
+
+    /**
+     * Binds this thread to given Fiber. Once set, Thread.currentThread() will
+     * return the Fiber rather than the Thread object for the carrier thread.
+     */
+    void setFiber(Fiber<?> fiber) {
+        //assert this == currentThread0();
+        this.fiber = fiber;
+    }
+
+    /**
+     * Returns the Fiber that is currently bound to this thread.
+     */
+    Fiber<?> getFiber() {
+        //assert this == currentThread0();
+        return fiber;
+    }
+
+    FiberScope scope() {
+        assert Thread.currentThread() == this;
+        return scope;
+    }
+
+    void setScope(FiberScope scope) {
+        assert Thread.currentThread() == this;
+        this.scope = scope;
+    }
 
     /**
      * A hint to the scheduler that the current thread is willing to yield
      * its current use of a processor. The scheduler is free to ignore this
      * hint.

@@ -272,11 +343,19 @@
      * for debugging or testing purposes, where it may help to reproduce
      * bugs due to race conditions. It may also be useful when designing
      * concurrency control constructs such as the ones in the
      * {@link java.util.concurrent.locks} package.
      */
-    public static native void yield();
+    public static void yield() {
+        Fiber<?> fiber = currentCarrierThread().getFiber();
+        if (fiber != null) {
+            fiber.yield();
+        } else {
+            yield0();
+        }
+    }
+    private static native void yield0();
 
     /**
      * Causes the currently executing thread to sleep (temporarily cease
      * execution) for the specified number of milliseconds, subject to
      * the precision and accuracy of system timers and schedulers. The thread

@@ -291,11 +370,21 @@
      * @throws  InterruptedException
      *          if any thread has interrupted the current thread. The
      *          <i>interrupted status</i> of the current thread is
      *          cleared when this exception is thrown.
      */
-    public static native void sleep(long millis) throws InterruptedException;
+    public static void sleep(long millis) throws InterruptedException {
+        if (millis < 0) {
+            throw new IllegalArgumentException("timeout value is negative");
+        }
+        if (currentCarrierThread().getFiber() != null) {
+            Fiber.sleepNanos(TimeUnit.MILLISECONDS.toNanos(millis));
+        } else {
+            sleep0(millis);
+        }
+    }
+    private static native void sleep0(long millis) throws InterruptedException;
 
     /**
      * Causes the currently executing thread to sleep (temporarily cease
      * execution) for the specified number of milliseconds plus the specified
      * number of nanoseconds, subject to the precision and accuracy of system

@@ -315,12 +404,11 @@
      * @throws  InterruptedException
      *          if any thread has interrupted the current thread. The
      *          <i>interrupted status</i> of the current thread is
      *          cleared when this exception is thrown.
      */
-    public static void sleep(long millis, int nanos)
-    throws InterruptedException {
+    public static void sleep(long millis, int nanos) throws InterruptedException {
         if (millis < 0) {
             throw new IllegalArgumentException("timeout value is negative");
         }
 
         if (nanos < 0 || nanos > 999999) {

@@ -450,10 +538,34 @@
         /* Set thread ID */
         this.tid = nextThreadID();
     }
 
     /**
+     * Initializes a Thread to be used as a shadow thread for Fibers.
+     */
+    Thread(ThreadGroup group,
+           String name,
+           ClassLoader contextClassLoader,
+           ThreadLocal.ThreadLocalMap inheritedLocals,
+           AccessControlContext inheritedAccessControlContext)
+    {
+        this.group = group;
+        this.name = name;
+        this.daemon = false;
+        this.priority = NORM_PRIORITY;
+        this.contextClassLoader = contextClassLoader;
+        if (inheritedLocals != null) {
+            this.inheritableThreadLocals = ThreadLocal.createInheritedMap(inheritedLocals);
+        } else {
+            this.inheritableThreadLocals = null;
+        }
+        this.inheritedAccessControlContext = inheritedAccessControlContext;
+        this.stackSize = 0;
+        this.tid = nextThreadID();
+    }
+
+    /**
      * Throws CloneNotSupportedException as a Thread can not be meaningfully
      * cloned. Construct a new Thread instead.
      *
      * @throws  CloneNotSupportedException
      *          always

@@ -890,10 +1002,12 @@
      * application if the uncaught exception is an instance of
      * {@code ThreadDeath}.
      *
      * @throws     SecurityException  if the current thread cannot
      *             modify this thread.
+     * @throws     UnsupportedOperationException if invoked on the Thread object
+     *             for a Fiber
      * @see        #interrupt()
      * @see        #checkAccess()
      * @see        #run()
      * @see        #start()
      * @see        ThreadDeath

@@ -926,10 +1040,14 @@
             checkAccess();
             if (this != Thread.currentThread()) {
                 security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
             }
         }
+
+        if (this instanceof ShadowThread)
+            throw new UnsupportedOperationException();
+
         // A zero status value corresponds to "NEW", it can't change to
         // not-NEW because we hold the lock.
         if (threadStatus != 0) {
             resume(); // Wake up thread if it was suspended; no-op otherwise
         }

@@ -1012,11 +1130,17 @@
      *          {@code false} otherwise.
      * @see #isInterrupted()
      * @revised 6.0
      */
     public static boolean interrupted() {
-        return currentThread().isInterrupted(true);
+        Thread thread = Thread.currentCarrierThread();
+        Fiber<?> fiber = thread.getFiber();
+        if (fiber != null) {
+            return fiber.isInterrupted(true);
+        } else {
+            return thread.isInterrupted(true);
+        }
     }
 
     /**
      * Tests whether this thread has been interrupted.  The <i>interrupted
      * status</i> of the thread is unaffected by this method.

@@ -1032,26 +1156,39 @@
      */
     public boolean isInterrupted() {
         return isInterrupted(false);
     }
 
+    void clearInterrupt() {
+        isInterrupted(true);
+    }
+
     /**
      * Tests if some Thread has been interrupted.  The interrupted state
-     * is reset or not based on the value of ClearInterrupted that is
+     * is reset or not based on the value of clearInterrupted that is
      * passed.
      */
     @HotSpotIntrinsicCandidate
-    private native boolean isInterrupted(boolean ClearInterrupted);
+    private native boolean isInterrupted(boolean clearInterrupted);
 
     /**
      * Tests if this thread is alive. A thread is alive if it has
      * been started and has not yet died.
      *
      * @return  {@code true} if this thread is alive;
      *          {@code false} otherwise.
      */
-    public final native boolean isAlive();
+    public final boolean isAlive() {
+        if (this instanceof ShadowThread) {
+            State state = getState();
+            assert state != State.NEW;
+            return (state != State.TERMINATED);
+        } else {
+            return isAlive0();
+        }
+    }
+    private native boolean isAlive0();
 
     /**
      * Suspends this thread.
      * <p>
      * First, the {@code checkAccess} method of this thread is called

@@ -1061,10 +1198,12 @@
      * If the thread is alive, it is suspended and makes no further
      * progress unless and until it is resumed.
      *
      * @throws     SecurityException  if the current thread cannot modify
      *             this thread.
+     * @throws     UnsupportedOperationException if invoked on the Thread object
+     *             for a Fiber
      * @see #checkAccess
      * @deprecated   This method has been deprecated, as it is
      *   inherently deadlock-prone.  If the target thread holds a lock on the
      *   monitor protecting a critical system resource when it is suspended, no
      *   thread can access this resource until the target thread is resumed. If

@@ -1076,10 +1215,16 @@
      *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      */
     @Deprecated(since="1.2")
     public final void suspend() {
         checkAccess();
+        if (this instanceof ShadowThread)
+            throw new UnsupportedOperationException();
+        suspend0();
+    }
+
+    void suspendThread() {
         suspend0();
     }
 
     /**
      * Resumes a suspended thread.

@@ -1091,10 +1236,12 @@
      * If the thread is alive but suspended, it is resumed and is
      * permitted to make progress in its execution.
      *
      * @throws     SecurityException  if the current thread cannot modify this
      *             thread.
+     * @throws     UnsupportedOperationException if invoked on the Thread object
+     *             for a Fiber
      * @see        #checkAccess
      * @see        #suspend()
      * @deprecated This method exists solely for use with {@link #suspend},
      *     which has been deprecated because it is deadlock-prone.
      *     For more information, see

@@ -1102,10 +1249,16 @@
      *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      */
     @Deprecated(since="1.2")
     public final void resume() {
         checkAccess();
+        if (this instanceof ShadowThread)
+            throw new UnsupportedOperationException();
+        resume0();
+    }
+
+    void resumeThread() {
         resume0();
     }
 
     /**
      * Changes the priority of this thread.

@@ -1172,11 +1325,11 @@
         if (name == null) {
             throw new NullPointerException("name cannot be null");
         }
 
         this.name = name;
-        if (threadStatus != 0) {
+        if (!(this instanceof ShadowThread) && threadStatus != 0) {
             setNativeName(name);
         }
     }
 
     /**

@@ -1285,27 +1438,34 @@
      * @throws  InterruptedException
      *          if any thread has interrupted the current thread. The
      *          <i>interrupted status</i> of the current thread is
      *          cleared when this exception is thrown.
      */
-    public final synchronized void join(final long millis)
-    throws InterruptedException {
-        if (millis > 0) {
-            if (isAlive()) {
-                final long startTime = System.nanoTime();
-                long delay = millis;
-                do {
-                    wait(delay);
-                } while (isAlive() && (delay = millis -
-                        TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
-            }
-        } else if (millis == 0) {
-            while (isAlive()) {
-                wait(0);
+    public final void join(long millis) throws InterruptedException {
+        if (this instanceof ShadowThread) {
+            Fiber<?> fiber = ((ShadowThread) this).fiber();
+            fiber.awaitInterruptibly(TimeUnit.MILLISECONDS.toNanos(millis));
+            return;
+        }
+
+        synchronized (this) {
+            if (millis > 0) {
+                if (isAlive()) {
+                    final long startTime = System.nanoTime();
+                    long delay = millis;
+                    do {
+                        wait(delay);
+                    } while (isAlive() && (delay = millis -
+                            TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
+                }
+            } else if (millis == 0) {
+                while (isAlive()) {
+                    wait(0);
+                }
+            } else {
+                throw new IllegalArgumentException("timeout value is negative");
             }
-        } else {
-            throw new IllegalArgumentException("timeout value is negative");
         }
     }
 
     /**
      * Waits at most {@code millis} milliseconds plus

@@ -1331,13 +1491,11 @@
      * @throws  InterruptedException
      *          if any thread has interrupted the current thread. The
      *          <i>interrupted status</i> of the current thread is
      *          cleared when this exception is thrown.
      */
-    public final synchronized void join(long millis, int nanos)
-    throws InterruptedException {
-
+    public final void join(long millis, int nanos) throws InterruptedException {
         if (millis < 0) {
             throw new IllegalArgumentException("timeout value is negative");
         }
 
         if (nanos < 0 || nanos > 999999) {

@@ -1380,11 +1538,13 @@
     }
 
     /**
      * Marks this thread as either a {@linkplain #isDaemon daemon} thread
      * or a user thread. The Java Virtual Machine exits when the only
-     * threads running are all daemon threads.
+     * threads running are all daemon threads. The daemon status of {@code
+     * Thread} objects associated with {@link Fiber}s is meaningless and does
+     * not determine if the Java Virtual Machine exits or not.
      *
      * <p> This method must be invoked before the thread is started.
      *
      * @param  on
      *         if {@code true}, marks this thread as a daemon thread

@@ -1485,10 +1645,24 @@
         }
         return contextClassLoader;
     }
 
     /**
+     * TBD
+     */
+    Continuation getContinuation() {
+        return cont;
+    }
+
+    /**
+     * TBD
+     */
+    void setContinuation(Continuation cont) {
+        this.cont = cont;
+    }
+
+    /**
      * Sets the context ClassLoader for this Thread. The context
      * ClassLoader can be set when a thread is created, and allows
      * the creator of the thread to provide the appropriate class loader,
      * through {@code getContextClassLoader}, to code running in the thread
      * when loading classes and resources.

@@ -1966,10 +2140,11 @@
     }
 
     /**
      * Set the handler invoked when this thread abruptly terminates
      * due to an uncaught exception.
+     *
      * <p>A thread can take full control of how it responds to uncaught
      * exceptions by having its uncaught exception handler explicitly set.
      * If no such handler is set then the thread's {@code ThreadGroup}
      * object acts as its handler.
      * @param eh the object to use as this thread's uncaught exception

@@ -1985,13 +2160,14 @@
         uncaughtExceptionHandler = eh;
     }
 
     /**
      * Dispatch an uncaught exception to the handler. This method is
-     * intended to be called only by the JVM.
+     * called by the VM when a thread terminates with an exception. It is also
+     * called when a fiber terminates with an exception.
      */
-    private void dispatchUncaughtException(Throwable e) {
+    void dispatchUncaughtException(Throwable e) {
         getUncaughtExceptionHandler().uncaughtException(this, e);
     }
 
     /**
      * Removes from the specified map any keys that have been enqueued
< prev index next >