Fix monitor methods. Improve JSO to handle abstract classes

This commit is contained in:
konsoletyper 2015-02-15 18:11:23 +04:00
parent 9d112817b8
commit b6cb9bfd4a
18 changed files with 437 additions and 100 deletions

View File

@ -0,0 +1,32 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TIllegalMonitorStateException extends TRuntimeException {
private static final long serialVersionUID = 7694307746228488658L;
public TIllegalMonitorStateException() {
super();
}
public TIllegalMonitorStateException(TString message) {
super(message);
}
}

View File

@ -16,14 +16,13 @@
package org.teavm.classlib.java.lang;
import org.teavm.dom.browser.TimerHandler;
import org.teavm.dom.browser.Window;
import org.teavm.javascript.spi.Async;
import org.teavm.javascript.spi.Rename;
import org.teavm.javascript.spi.Superclass;
import org.teavm.jso.JS;
import org.teavm.jso.JSArray;
import org.teavm.jso.JSObject;
import org.teavm.javascript.spi.Sync;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformQueue;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
/**
@ -32,51 +31,97 @@ import org.teavm.platform.async.AsyncCallback;
*/
@Superclass("")
public class TObject {
private static final Window window = (Window)JS.getGlobal();
private JSArray<NotifyListener> notifyListeners;
private Lock lock;
Monitor monitor;
private static class Lock {
static class Monitor {
PlatformQueue<PlatformRunnable> enteringThreads;
PlatformQueue<NotifyListener> notifyListeners;
TThread owner;
int count;
public Lock() {
public Monitor() {
this.owner = TThread.currentThread();
count = 1;
enteringThreads = Platform.createQueue();
notifyListeners = Platform.createQueue();
}
}
interface NotifyListener extends JSObject {
boolean handleNotify();
interface NotifyListener extends PlatformRunnable {
boolean expired();
}
static void monitorEnter(TObject o) {
if (o.lock == null) {
o.lock = new Lock();
return;
monitorEnter(o, 1);
}
if (o.lock.owner != TThread.currentThread()) {
while (o.lock != null) {
try {
o.lock.wait();
} catch (InterruptedException ex) {
@Async
static native void monitorEnter(TObject o, int count);
static void monitorEnter(final TObject o, final int count, final AsyncCallback<Void> callback) {
if (o.monitor == null) {
o.monitor = new Monitor();
}
if (o.monitor.owner == null) {
o.monitor.owner = TThread.currentThread();
}
o.lock = new Lock();
if (o.monitor.owner != TThread.currentThread()) {
final TThread thread = TThread.currentThread();
o.monitor.enteringThreads.add(new PlatformRunnable() {
@Override public void run() {
TThread.setCurrentThread(thread);
o.monitor.owner = thread;
o.monitor.count += count;
callback.complete(null);
};
});
} else {
o.lock.count++;
o.monitor.count += count;
callback.complete(null);
}
}
static void monitorExit(TObject o){
if (o.lock != null && o.lock.count-- == 0) {
o.lock.notifyAll();
o.lock = null;
@Sync
static void monitorExit(final TObject o) {
monitorExit(o, 1);
}
@Sync
static void monitorExit(final TObject o, int count) {
if (o.isEmptyMonitor() || o.monitor.owner != TThread.currentThread()) {
throw new TIllegalMonitorStateException();
}
o.monitor.count -= count;
if (o.monitor.count > 0) {
return;
}
o.monitor.owner = null;
Platform.startThread(new PlatformRunnable() {
@Override public void run() {
if (o.isEmptyMonitor() || o.monitor.owner != null) {
return;
}
if (!o.monitor.enteringThreads.isEmpty()) {
o.monitor.enteringThreads.remove().run();
}
}
});
}
boolean isEmptyMonitor() {
if (monitor == null) {
return true;
}
if (monitor.owner == null && monitor.enteringThreads.isEmpty() && monitor.notifyListeners.isEmpty()) {
monitor = null;
return true;
} else {
return false;
}
}
static boolean holdsLock(TObject o) {
return o.lock != null && o.lock.owner == TThread.currentThread();
return o.monitor != null && o.monitor.owner == TThread.currentThread();
}
@Rename("fakeInit")
@ -123,30 +168,35 @@ public class TObject {
return result;
}
@Sync
@Rename("notify")
public final void notify0() {
TThread thread = TThread.currentThread();
if (notifyListeners != null) {
while (notifyListeners.getLength() > 0 && notifyListeners.shift().handleNotify()) {
// repeat loop
if (!holdsLock(this)) {
throw new TIllegalMonitorStateException();
}
if (notifyListeners.getLength() == 0) {
notifyListeners = null;
TThread thread = TThread.currentThread();
PlatformQueue<NotifyListener> listeners = monitor.notifyListeners;
while (!listeners.isEmpty()) {
NotifyListener listener = listeners.remove();
if (!listener.expired()) {
Platform.startThread(listener);
break;
}
}
TThread.setCurrentThread(thread);
}
@Sync
@Rename("notifyAll")
public final void notifyAll0() {
if (notifyListeners != null){
JSArray<NotifyListener> listeners = window.newArray();
while (notifyListeners.getLength() > 0) {
listeners.push(notifyListeners.shift());
if (!holdsLock(this)) {
throw new TIllegalMonitorStateException();
}
notifyListeners = null;
while (listeners.getLength() > 0) {
listeners.shift().handleNotify();
PlatformQueue<NotifyListener> listeners = monitor.notifyListeners;
while (!listeners.isEmpty()) {
NotifyListener listener = listeners.remove();
if (!listener.expired()) {
Platform.startThread(listener);
}
}
}
@ -166,49 +216,51 @@ public class TObject {
@Rename("wait")
public final void wait0(long timeout, int nanos, final AsyncCallback<Void> callback) {
if (notifyListeners == null) {
notifyListeners = window.newArray();
final NotifyListenerImpl listener = new NotifyListenerImpl(this, callback, monitor.count);
monitor.notifyListeners.add(listener);
if (timeout > 0 || nanos > 0) {
listener.timerId = Platform.schedule(listener, timeout >= Integer.MAX_VALUE ? Integer.MAX_VALUE :
(int)timeout);
}
final NotifyListenerImpl listener = new NotifyListenerImpl(callback);
notifyListeners.push(listener);
if (timeout == 0 && nanos == 0) {
return;
}
listener.timerId = window.setTimeout(listener, timeout);
monitorExit(this, monitor.count);
}
private static class NotifyListenerImpl implements NotifyListener, TimerHandler {
private static class NotifyListenerImpl implements NotifyListener, TimerHandler, PlatformRunnable {
final TObject obj;
final AsyncCallback<Void> callback;
final TThread currentThread = TThread.currentThread();
int timerId = -1;
boolean finished;
boolean expired;
int lockCount;
public NotifyListenerImpl(AsyncCallback<Void> callback) {
public NotifyListenerImpl(TObject obj, AsyncCallback<Void> callback, int lockCount) {
this.obj = obj;
this.callback = callback;
this.lockCount = lockCount;
}
@Override
public boolean handleNotify() {
if (finished) {
return false;
}
TThread.setCurrentThread(currentThread);
if (timerId >= 0) {
window.clearTimeout(timerId);
timerId = -1;
}
finished = true;
try {
callback.complete(null);
} finally {
TThread.setCurrentThread(TThread.getMainThread());
}
return true;
public boolean expired() {
boolean result = expired;
expired = true;
return result;
}
@Override
public void onTimer() {
handleNotify();
if (!expired()) {
Platform.startThread(this);
}
}
@Override
public void run() {
if (timerId >= 0) {
Platform.killSchedule(timerId);
timerId = -1;
}
TThread.setCurrentThread(currentThread);
monitorEnter(obj, lockCount, callback);
}
}

View File

@ -20,6 +20,7 @@ import org.teavm.dom.browser.Window;
import org.teavm.javascript.spi.Async;
import org.teavm.jso.JS;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
@ -57,7 +58,7 @@ public class TThread extends TObject implements TRunnable {
}
public void start(){
Platform.startThread(new Runnable() {
Platform.startThread(new PlatformRunnable() {
@Override
public void run() {
try {
@ -98,14 +99,7 @@ public class TThread extends TObject implements TRunnable {
public static native void yield();
private static void yield(final AsyncCallback<Void> callback) {
final TThread current = currentThread();
window.setTimeout(new TimerHandler() {
@Override public void onTimer() {
setCurrentThread(current);
callback.complete(null);
setCurrentThread(mainThread);
}
}, 0);
}
public void interrupt() {
@ -140,7 +134,6 @@ public class TThread extends TObject implements TRunnable {
@Override public void onTimer() {
setCurrentThread(current);
callback.complete(null);
setCurrentThread(mainThread);
}
}, millis);
}

View File

@ -205,6 +205,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
renderRuntimeObjcls();
renderRuntimeNullCheck();
renderRuntimeIntern();
renderRuntimeThreads();
} catch (NamingException e) {
throw new RenderingException("Error rendering runtime methods. See a cause for details", e);
} catch (IOException e) {
@ -270,6 +271,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append("function $rt_objcls() { return ").appendClass("java.lang.Object").append("; }").newLine();
}
private void renderRuntimeThreads() throws IOException {
writer.append("function $rt_getThread()").ws().append("{").indent().softNewLine();
writer.append("return ").appendMethodBody(Thread.class, "currentThread", Thread.class).append("();")
.softNewLine();
writer.outdent().append("}").newLine();
writer.append("function $rt_setThread(t)").ws().append("{").indent().softNewLine();
writer.append("return ").appendMethodBody(Thread.class, "setCurrentThread", Thread.class, void.class)
.append("(t);").softNewLine();
writer.outdent().append("}").newLine();
}
public void render(List<ClassNode> classes) throws RenderingException {
for (ClassNode cls : classes) {
renderDeclaration(cls);

View File

@ -15,10 +15,7 @@
*/
package org.teavm.javascript.spi;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
*
@ -26,5 +23,6 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface Sync {
}

View File

@ -35,6 +35,9 @@ public class AsyncProgramSplitter {
}
public void split(Program program) {
System.out.println("Splitting program");
System.out.println(new ListingBuilder().buildListing(program, " "));
parts.clear();
Program initialProgram = createStubCopy(program);
Part initialPart = new Part();
@ -145,6 +148,13 @@ public class AsyncProgramSplitter {
}
}
for (int i = 0; i < parts.size(); ++i) {
Program part = parts.get(i).program;
System.out.println("Part " + i);
System.out.println(new ListingBuilder().buildListing(part, " "));
}
System.out.println();
partMap.clear();
}

View File

@ -464,8 +464,9 @@ function $rt_asyncAdapter(f) {
var result;
var args = Array.prototype.slice.apply(arguments);
var $return = args.pop();
args.unshift(this);
try {
result = f.apply(this, args);
result = f.apply(null, args);
} catch (e) {
return $return($rt_asyncError(e));
}
@ -510,7 +511,9 @@ function $rt_continue(f) {
return function() {
var self = this;
var args = arguments;
var thread = $rt_getThread();
setTimeout(function() {
$rt_setThread(thread);
f.apply(self, args);
}, 0);
};

View File

@ -132,7 +132,7 @@ class JSODependencyListener implements DependencyListener {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
public void methodAchieved(DependencyAgent agent, MethodDependency methodDep, CallLocation location) {
}
@Override

View File

@ -31,6 +31,9 @@ public class JSObjectClassTransformer implements ClassHolderTransformer {
processor = new JavascriptNativeProcessor(innerSource);
processor.setDiagnostics(diagnostics);
processor.processClass(cls);
if (processor.isNative(cls.getName())) {
processor.processFinalMethods(cls);
}
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
if (method.getAnnotations().get(JSBody.class.getName()) != null) {
processor.processJSBody(cls, method);

View File

@ -21,6 +21,8 @@ import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.jso.*;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.util.InstructionVariableMapper;
import org.teavm.model.util.ProgramUtils;
/**
*
@ -39,6 +41,10 @@ class JavascriptNativeProcessor {
nativeRepos = new NativeJavascriptClassRepository(classSource);
}
public boolean isNative(String className) {
return nativeRepos.isJavaScriptClass(className);
}
public void setDiagnostics(Diagnostics diagnostics) {
this.diagnostics = diagnostics;
}
@ -62,6 +68,47 @@ class JavascriptNativeProcessor {
}
}
public void processFinalMethods(ClassHolder cls) {
// TODO: don't allow final methods to override anything
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
if (method.hasModifier(ElementModifier.FINAL) && method.getProgram() != null) {
ValueType[] staticSignature = getStaticSignature(method.getReference());
MethodHolder callerMethod = new MethodHolder(new MethodDescriptor(method.getName() + "$static",
staticSignature));
callerMethod.getModifiers().add(ElementModifier.STATIC);
final Program program = ProgramUtils.copy(method.getProgram());
program.createVariable();
InstructionVariableMapper variableMapper = new InstructionVariableMapper() {
@Override protected Variable map(Variable var) {
return program.variableAt(var.getIndex() + 1);
}
};
for (int i = program.variableCount() - 1; i > 0; --i) {
program.variableAt(i).getDebugNames().addAll(program.variableAt(i - 1).getDebugNames());
program.variableAt(i - 1).getDebugNames().clear();
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(variableMapper);
}
}
callerMethod.setProgram(program);
cls.addMethod(callerMethod);
}
}
}
private static ValueType[] getStaticSignature(MethodReference method) {
ValueType[] signature = method.getSignature();
ValueType[] staticSignature = new ValueType[signature.length + 1];
for (int i = 0; i < signature.length; ++i) {
staticSignature[i + 1] = signature[i];
}
staticSignature[0] = ValueType.object(method.getClassName());
return staticSignature;
}
public void processProgram(MethodHolder methodToProcess) {
program = methodToProcess.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -78,6 +125,17 @@ class JavascriptNativeProcessor {
}
replacement.clear();
MethodReader method = getMethod(invoke.getMethod());
if (method.hasModifier(ElementModifier.STATIC)) {
continue;
}
if (method.hasModifier(ElementModifier.FINAL)) {
invoke.setMethod(new MethodReference(method.getOwnerName(), method.getName() + "$static",
getStaticSignature(method.getReference())));
invoke.setType(InvocationType.SPECIAL);
invoke.getArguments().add(0, invoke.getInstance());
invoke.setInstance(null);
continue;
}
CallLocation callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
if (method.getAnnotations().get(JSProperty.class.getName()) != null) {
if (isProperGetter(method.getDescriptor())) {

View File

@ -46,7 +46,7 @@ class NativeJavascriptClassRepository {
private boolean figureOutIfJavaScriptClass(String className) {
ClassReader cls = classSource.get(className);
if (cls == null || !cls.hasModifier(ElementModifier.INTERFACE)) {
if (cls == null || !(cls.hasModifier(ElementModifier.INTERFACE) || cls.hasModifier(ElementModifier.ABSTRACT))) {
return false;
}
for (String iface : cls.getInterfaces()) {

View File

@ -94,12 +94,24 @@ public final class Platform {
@GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
public static native void startThread(Runnable runnable);
public static native void startThread(PlatformRunnable runnable);
private static void launchThread(Runnable runnable) {
private static void launchThread(PlatformRunnable runnable) {
runnable.run();
}
@GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
public static native int schedule(PlatformRunnable runnable, int timeout);
public static void killSchedule(int id) {
((PlatformHelper)JS.getGlobal()).killSchedule(id);
}
public static <T> PlatformQueue<T> createQueue() {
return ((PlatformHelper)JS.getGlobal()).newQueue();
}
public static PlatformString stringFromCharCode(int charCode) {
return ((PlatformHelper)JS.getGlobal()).getStringClass().fromCharCode(charCode);
}

View File

@ -15,6 +15,7 @@
*/
package org.teavm.platform;
import org.teavm.jso.JSConstructor;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
@ -29,4 +30,10 @@ interface PlatformHelper extends JSObject {
@JSProperty("String")
PlatformStringClass getStringClass();
@JSConstructor("Array")
<T> PlatformQueue<T> newQueue();
@JSMethod("clearTimeout")
void killSchedule(int scheduleId);
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.platform;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.spi.InjectedBy;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.platform.plugin.PlatformQueueGenerator;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public abstract class PlatformQueue<T> implements JSObject {
@JSProperty
public abstract int getLength();
public final boolean isEmpty() {
return getLength() == 0;
}
abstract void push(PlatformObject obj);
abstract PlatformObject shift();
public final void add(T e) {
push(wrap(e));
}
public final T remove() {
return unwrap(shift());
}
private static PlatformObject wrap(Object obj) {
return Platform.getPlatformObject(obj);
}
@InjectedBy(PlatformQueueGenerator.class)
@PluggableDependency(PlatformQueueGenerator.class)
private static native <S> S unwrap(PlatformObject obj);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.platform;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface PlatformRunnable {
void run();
}

View File

@ -26,6 +26,7 @@ import org.teavm.javascript.spi.Injector;
import org.teavm.javascript.spi.InjectorContext;
import org.teavm.model.*;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformRunnable;
/**
*
@ -41,9 +42,10 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
case "clone":
method.getVariable(1).connect(method.getResult());
break;
case "startThread": {
case "startThread":
case "schedule": {
MethodDependency launchMethod = agent.linkMethod(new MethodReference(Platform.class,
"launchThread", Runnable.class, void.class), null);
"launchThread", PlatformRunnable.class, void.class), null);
method.getVariable(1).connect(launchMethod.getVariable(1));
launchMethod.use();
break;
@ -78,7 +80,10 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
generateClone(context, writer);
break;
case "startThread":
generateStartThread(context, writer);
generateSchedule(context, writer, false);
break;
case "schedule":
generateSchedule(context, writer, true);
break;
}
}
@ -129,11 +134,12 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
writer.append("return copy;").softNewLine();
}
private void generateStartThread(GeneratorContext context, SourceWriter writer) throws IOException {
private void generateSchedule(GeneratorContext context, SourceWriter writer, boolean timeout) throws IOException {
String runnable = context.getParameterName(1);
writer.append("window.setTimeout(function()").ws().append("{").indent().softNewLine();
writer.append("$rt_rootInvocationAdapter(").appendMethodBody(Platform.class, "launchThread", Runnable.class,
void.class).append(")(").append(runnable).append(");").softNewLine();
writer.outdent().append("},").ws().append("0);").softNewLine();
writer.append("return window.setTimeout(function()").ws().append("{").indent().softNewLine();
writer.append("$rt_rootInvocationAdapter(").appendMethodBody(Platform.class, "launchThread",
PlatformRunnable.class, void.class).append(")(").append(runnable).append(");").softNewLine();
writer.outdent().append("},").ws().append(timeout ? context.getParameterName(2) : "0")
.append(");").softNewLine();
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.platform.plugin;
import java.io.IOException;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.spi.Injector;
import org.teavm.javascript.spi.InjectorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
import org.teavm.platform.PlatformObject;
import org.teavm.platform.PlatformQueue;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class PlatformQueueGenerator implements Injector, DependencyPlugin {
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
MethodDependency addMethod = agent.linkMethod(new MethodReference(PlatformQueue.class, "wrap",
Object.class, PlatformObject.class), null);
addMethod.getVariable(1).connect(method.getResult());
}
@Override
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
context.writeExpr(context.getArgument(0));
}
}

View File

@ -29,6 +29,7 @@ public final class AsyncProgram {
public static void main(String[] args) throws InterruptedException {
report(Arrays.toString(args));
findPrimes();
withoutAsync();
report("");
withAsync();
@ -64,11 +65,36 @@ public final class AsyncProgram {
report("Now trying wait...");
synchronized (lock) {
report("Lock acquired");
lock.wait(20000);
}
report("Finished main thread");
}
private static void findPrimes() {
report("Finding primes");
boolean[] prime = new boolean[1000];
prime[2] = true;
prime[3] = true;
nextPrime: for (int i = 5; i < prime.length; i += 2) {
int maxPrime = (int)Math.sqrt(i);
for (int j = 3; j <= maxPrime; j += 2) {
Thread.yield();
if (prime[j] && i % j == 0) {
continue nextPrime;
}
}
prime[i] = true;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; ++i) {
if (prime[i]) {
sb.append(i).append(' ');
}
}
report(sb.toString());
}
private static void report(String message) {
long current = System.currentTimeMillis() - start;
System.out.println("[" + Thread.currentThread().getName() + "]/" + current + ": " + message);