【发布时间】:2012-10-17 23:33:30
【问题描述】:
我正在努力回忆我以前的 CS 岁月。
一直在尝试以尽可能低的原语正确实现一对同步线程。当然,我应该在生产代码上使用更好的并发工具(可能来自 java.util.concurrency 的东西)。但是,嘿,我这样做是为了挑战。这是我的代码(这是我的第一个问题,所以如果这太长了,请原谅我):
public class Test {
public volatile Object locker1 = new Object();
public volatile Object locker2 = new Object();
public volatile Object locker3 = new Object();
public class MyRunnable2 implements Runnable {
public void run() {
System.out.println( "MyRunnable2 started" );
synchronized( locker3 ) {
try {
System.out.println( "r2: waiting for locker3" );
locker3.wait();
System.out.println( "r2: got locker3" );
} catch ( java.lang.InterruptedException e ) {
System.out.println( "e: " + e );
}
}
for ( int c = 0; c < 50; ++c ) {
synchronized( locker2 ) {
try {
System.out.println( "r2: waiting for locker2" );
locker2.wait();
System.out.println( "r2: got locker2" );
} catch ( java.lang.InterruptedException e ) {
System.out.println( "e: " + e );
}
}
System.out.println( "r2: " + ( c ) );
try {
Thread.sleep(1);
} catch ( Exception e ) {
}
synchronized( locker1 ) {
System.out.println( "r2: signaling locker1" );
locker1.notify();
System.out.println( "r2: locker1 signaled" );
}
}
}
}
public class MyRunnable1 implements Runnable {
public void run() {
System.out.println( "MyRunnable1 started" );
synchronized( locker3 ) {
try {
System.out.println( "r1: waiting for locker3" );
locker3.wait();
System.out.println( "r1: got locker3" );
} catch ( java.lang.InterruptedException e ) {
System.out.println( "e: " + e );
}
}
for ( int c = 0; c < 50; ++c ) {
synchronized( locker1 ) {
try {
System.out.println( "r1: waiting for locker1" );
locker1.wait();
System.out.println( "r1: got locker1" );
} catch ( java.lang.InterruptedException e ) {
System.out.println( "e: " + e );
}
}
System.out.println( "r1: " + ( c ) );
try {
Thread.sleep(1);
} catch ( Exception e ) {
}
synchronized( locker2 ) {
System.out.println( "r1: signaling locker2" );
locker2.notify();
System.out.println( "r1: locker2 signaled" );
}
}
}
}
public static void main(String[] args) {
Test t = new Test();
t.test();
}
public void test() {
MyRunnable1 r1 = new MyRunnable1();
MyRunnable2 r2 = new MyRunnable2();
Thread t1 = new Thread( r1 );
Thread t2 = new Thread( r2 );
t1.start();
t2.start();
try {
Thread.sleep(1000);
} catch ( Exception e ) {
}
synchronized( locker3 ) {
System.out.println( "main: signaling locker3" );
locker3.notifyAll();
System.out.println( "main: locker3 signaled" );
}
try {
Thread.sleep(1000);
} catch ( Exception e ) {
}
synchronized( locker1 ) {
System.out.println( "main: signaling locker1" );
locker1.notify();
System.out.println( "main: locker1 signaled" );
}
try {
t1.join();
t2.join();
} catch ( java.lang.InterruptedException e ) {
System.out.println( "e: " + e );
}
}
}
我的问题是:如何避免 Test.test() 的竞争条件?大多数情况下,这是可行的——但我对睡眠电话不满意。 另外,请大家评价一下我的风格。我总是乐于自我提升。
编辑:只是为了更清楚。我希望 MyRunnable1 始终先运行。打印一个数字,然后等待 MyRunnable2 打印相同的数字。然后它会打印第二个数字,然后再次等待 MyRunnable2。以此类推。
我想我不能舒适地使用 java.util.concurrency,直到我知道引擎盖下发生了什么。
【问题讨论】:
-
根据您的旧 CS 时代是多久以前,并发世界可能发生了很大变化。如今,内存和缓存优化做了一些真正奇怪的事情,您尝试访问同步块之外的共享值。查看 Java Concurrency in Practice 以获得关于如何考虑并发问题的非常好的描述。至于这个问题,您要消除的竞争条件是什么?您要强制执行的行为是什么?您希望线程一个接一个地轮流运行吗?
-
没错,@Superboggly。我希望 MyRunnable1 始终先运行,打印一个数字,然后让位于 MyRunnable2 以打印相同的数字。两个线程总是在同一个地方停下来。编辑问题以使其更清晰。
标签: java multithreading wait synchronized notify