Java的线程同步功能似乎不是百分百准确的。这个示例的代码会打印一个静态整数的值,该整数被每个线程递增。如果输出重复包含相同的数字,则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 ) {
ArrayList <Thread>al = new ArrayList<Thread>();
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 ) {
ArrayList <Thread>al = new ArrayList<Thread>();
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相同,只是使用了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 ) {
ArrayList <Thread>al = new ArrayList<Thread>();
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 ) {
ArrayList <Thread>al = new ArrayList<Thread>();
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 ) {
ArrayList <Thread>al = new ArrayList<Thread>();
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();
}
}
}
当代码运行时,上述线程同步方法并不能百分之百地保证有效。有什么想法是哪里出了问题?
adder()
更改为静态同步。 - Andrew Williamson