Strange problem with simple multithreading program in Java
I am just starting play with multithreading programming. I would like to my program show alternately character '-' and '+' but it doesn't. My task is to use synchronized
keyword. As far I have:
class FunnyStringGenerator{
private char c;
public FunnyStringGenerator(){
c = '-';
}
public synchronized char next(){
if(c == '-'){
c = '+';
}
else{
c = '-';
}
return c;
}
}
c开发者_运维技巧lass ThreadToGenerateStr implements Runnable{
FunnyStringGenerator gen;
public ThreadToGenerateStr(FunnyStringGenerator fsg){
gen = fsg;
}
@Override
public void run() {
for(int i = 0; i < 10; i++){
System.out.print(gen.next());
}
}
}
public class Main{
public static void main(String[] args) throws IOException {
FunnyStringGenerator FSG = new FunnyStringGenerator();
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0; i < 20; i++){
exec.execute(new ThreadToGenerateStr(FSG));
}
}
}
EDIT: I also testing Thread.sleep
in run method instead for
loop.
Your synchronized
block in FunnyStringGenerator.next()
is working fine. It will return '+'
and '-'
alternately.
However you have a race condition in ThreadToGenerateStr.run()
:
System.out.print(gen.next());
This is equivalent to:
char c = gen.next(); // Synchronized
System.out.print(c); // Not synchronized
The problem occurs when:
- Thread 1 calls gen.next(), getting a result of '-'
- Thread 2 calls gen.next(), getting a result of '+'
- Thread 2 calls System.out.print(), writing '+'
- Thread 1 calls System.out.print(), writing '-'
The result is that the '+' and '-' are written in the opposite order.
There are various possible workarounds, e.g.:
- Call both gen.next() and System.out.print() in a single
synchronized
block (as in dogbane's answer) - Make gen.next() write the character to the stream instead of returning it
- Make gen.next() append the character to a shared BlockingQueue and have a dedicated I/O thread taking characters from this queue and printing them.
Instead of synchronizing the method, do this:
synchronized (gen) {
System.out.print(gen.next());
}
You need to wrap the entire print statement in a synchronized block so that another thread cannot change the value of c
before you print it.
Think of it as two statements:
char n = gen.next();
System.out.print(n);
Please use two threads for printing each character and use this concept of wait and notify.
精彩评论