使用线程同步,Java似乎不是100%准确.此示例中的代码打印一个静态整数的值,该值由每个线程递增.如果输出包含相同的数字,uniq将多次识别它.每个示例都由Makefile脚本运行,以帮助说明问题.每个示例使用不同的同步/锁定方法,但似乎没有一个方法在100%的时间内都能正常工作.大多数复制发生在循环的早期,至少在这个系统上.
Makefile文件:
JAVA=/usr/local/jdk/bin/java JAVAC=$(JAVA)c build: $(JAVAC) Synchron.java $(JAVAC) SynchronVolatile.java $(JAVAC) SynchronFinal.java $(JAVAC) SynchronThis.java $(JAVAC) SynchronA.java $(JAVAC) SynchronObj.java run: $(JAVA) Synchron | sort | uniq -c | egrep -v '^\s+1\s+' ; /bin/true $(JAVA) SynchronVolatile | sort | uniq -c | egrep -v '^\s+1\s+' ; /bin/true $(JAVA) SynchronFinal | sort | uniq -c | egrep -v '^\s+1\s+' ; /bin/true $(JAVA) SynchronThis | sort | uniq -c | egrep -v '^\s+1\s+' ; /bin/true $(JAVA) SynchronA | sort | uniq -c | egrep -v '^\s+1\s+' ; /bin/true $(JAVA) SynchronObj | sort | uniq -c | egrep -v '^\s+1\s+' ; /bin/true
Synchron.java:
import java.io.*; import java.util.*; public class Synchron implements Runnable { static int a; synchronized public void adder() { Synchron.a++; System.out.println( Synchron.a ); } public void run() { while( Synchron.a < 65535 ) { adder(); } } public static void main( String []args ) { ArrayListal = new ArrayList (); try { int i; for( i = 0; i<10 ; i++ ) { Synchron s = new Synchron(); Thread t = new Thread( s ); al.add(t); t.start(); } for( Thread t : al ) { t.join(); } } catch( Exception e ) { e.printStackTrace(); } } }
SynchronVolatile.java:
import java.io.*; import java.util.*; public class SynchronVolatile implements Runnable { static int a; static volatile Object o = new Object(); public void adder() { synchronized( SynchronVolatile.o ) { SynchronVolatile.a++; } System.out.println( SynchronVolatile.a ); } public void run() { while( SynchronVolatile.a < 65535 ) { adder(); } } public static void main( String []args ) { ArrayListal = new ArrayList (); try { int i; for( i = 0; i<10 ; i++ ) { SynchronVolatile s = new SynchronVolatile(); Thread t = new Thread( s ); al.add(t); t.start(); } for( Thread t : al ) { t.join(); } } catch( Exception e ) { e.printStackTrace(); } } }
SynchronFinal:这与SynchronVolatile.java相同,除了它使用Object o的final,而不是volatile.
SynchronThis.java:
import java.io.*; import java.util.*; public class SynchronThis implements Runnable { static int a; static volatile Object o = new Object(); public void adder() { synchronized( this ) { SynchronThis.a++; } System.out.println( SynchronThis.a ); } public void run() { while( SynchronThis.a < 65535 ) { adder(); } } public static void main( String []args ) { ArrayListal = new ArrayList (); try { int i; for( i = 0; i<10 ; i++ ) { SynchronThis s = new SynchronThis(); Thread t = new Thread( s ); al.add(t); t.start(); } for( Thread t : al ) { t.join(); } } catch( Exception e ) { e.printStackTrace(); } } }
SynchronA.java:
import java.io.*; import java.util.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class SynchronA implements Runnable { static int a; private volatile Lock lock = new ReentrantLock(); public void adder() { lock.lock(); SynchronA.a++; System.out.println( SynchronA.a ); lock.unlock(); } public void run() { while( SynchronA.a < 65535 ) { adder(); } } public static void main( String []args ) { ArrayListal = new ArrayList (); try { int i; for( i = 0; i<10 ; i++ ) { SynchronA s = new SynchronA(); Thread t = new Thread( s ); al.add(t); t.start(); } for( Thread t : al ) { t.join(); } } catch( Exception e ) { e.printStackTrace(); } } }
SynchronObj.java:
import java.io.*; import java.util.*; public class SynchronObj implements Runnable { static int a; Object o; public SynchronObj( Object obj ) { o = obj; } public void adder() { synchronized( o ) { SynchronObj.a++; } System.out.println( SynchronObj.a ); } public void run() { while( SynchronObj.a < 65535 ) { adder(); } } public static void main( String []args ) { ArrayListal = new ArrayList (); final Object o = new Object(); try { int i; for( i = 0; i<10 ; i++ ) { SynchronObj s = new SynchronObj( o ); Thread t = new Thread( s ); al.add(t); t.start(); } for( Thread t : al ) { t.join(); } } catch( Exception e ) { e.printStackTrace(); } } }
当它运行时,上面的线程同步方法都没有100%的时间工作.什么可能出错?
您的问题是,在某些情况下,您的锁定锁定在不同的锁定对象实例上,因此它们实际上从不干扰其他锁定.
更改
Object o;
至
public static final Object o = new Object();
现在,您的所有synchronized
语句都将尝试锁定同一个对象,并且将发生正确的锁争用.
这看起来很可疑:
while (SynchronObj.a < 65535) {...}
因为你正在读取没有同步的a的值.绝对是一个问题.
您的同步测试方法似乎也是通过搜索打印的重复输出.相反,尝试做
public void run() { for (int i=0; i<10000; i++) { adder(); } }
因为您正在运行10个线程,所以只需验证最终答案是否正确10000*10
.任何更少/更多将暗示不正确的线程同步.