1 /* 2 * Copyright 2010 Google, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 import java.util.LinkedList; 26 import sun.misc.Continuation; 27 28 /* 29 * This class demonstrates the continuation feature by implementing a 30 * user-thread-like object. 31 */ 32 public class ContinuationTest9 { 33 private static int ITER = 10000; 34 35 public static void test() throws Exception { 36 Runnable r1 = new Runnable() { 37 public void run() { 38 while (true) { 39 System.out.println("t1: " + counter++); 40 UserThread.yield(); 41 if (counter > ITER) { 42 return; 43 } 44 } 45 }}; 46 Runnable r2 = new Runnable() { 47 public void run() { 48 while (true) { 49 System.out.println("t2: " + counter++); 50 UserThread.yield(); 51 if (counter > ITER) { 52 return; 53 } 54 } 55 }}; 56 UserThread t1 = new UserThread(r1); 57 UserThread t2 = new UserThread(r2); 58 t1.start(); 59 t2.start(); 60 UserThread.join(); 61 } 62 63 private static int counter = 0; 64 65 public static void main(String[] args) throws Exception { 66 test(); 67 System.exit(0); 68 } 69 } 70 71 class UserThread { 72 // The schedule queue 73 private static final LinkedList<UserThread> queue = new LinkedList<UserThread>(); 74 // The currently scheduled UserThread 75 private static UserThread currentThread; 76 // Used to synchronize between the internal thread and the outside world 77 // This guards queue, nthreads and currentThread 78 private static final Object lock = new Object(); 79 // The number of live UserThreads 80 private static int nthreads = 0; 81 // Lock for join 82 private static final Object awaitLock = new Object(); 83 84 // The backing Java thread that executes 85 // all UserThreads 86 private static final Thread jthread = 87 new Thread(new Runnable() { 88 public void run() { 89 while (true) { 90 try { 91 UserThread ut_to_run; 92 synchronized (lock) { 93 if (queue.size() == 0) { 94 // Wait if there's no user thread to schedule 95 lock.wait(); 96 } 97 // Get the user thread to be scheduled next 98 ut_to_run = queue.remove(); 99 currentThread = ut_to_run; 100 } 101 final UserThread ut = ut_to_run; 102 final Continuation c = ut.continuation; 103 // If it's scheduled for the first time, 104 if (c == null) { 105 // simply execute the given Runnable in a scope 106 Continuation.enter(ut.runnable, null); 107 } else { 108 // Otherwise, resume the saved continuation 109 Runnable r = new Runnable() { 110 public void run() { 111 c.resume(null); 112 }}; 113 Continuation.enter(r, null); 114 } 115 } catch (Throwable t) { 116 throw new RuntimeException(t); 117 } 118 } 119 } 120 }); 121 122 static { 123 jthread.start(); 124 } 125 126 private final Runnable runnable; 127 private Continuation continuation; 128 129 public UserThread(final Runnable r) { 130 runnable = new Runnable() { 131 public void run() { 132 r.run(); 133 UserThread.exit(); 134 } 135 }; 136 } 137 138 public void start() { 139 synchronized(lock) { 140 nthreads++; 141 // Add the given user thread to the schedule queue 142 queue.add(this); 143 // Notify the Java thread if it's waiting 144 lock.notify(); 145 } 146 } 147 148 public static void yield() { 149 // Create a new continuation for each yield 150 final Continuation c = new Continuation(); 151 synchronized (lock) { 152 // Save it in the user thread 153 currentThread.continuation = c; 154 // Put the user thread back to the schedule queue 155 queue.add(currentThread); 156 } 157 // Save the current scope into it. It will cause 158 // the enter at the bottom of the scope to return. 159 c.save(); 160 } 161 162 private static void exit() { 163 int new_nthreads; 164 synchronized (lock) { 165 nthreads--; 166 new_nthreads = nthreads; 167 if (new_nthreads == 0) { 168 synchronized (awaitLock) { 169 awaitLock.notify(); 170 } 171 } 172 } 173 } 174 175 public static void join() throws InterruptedException { 176 synchronized (awaitLock) { 177 awaitLock.wait(); 178 } 179 } 180 }