.
class Account implements Runnable {
private int total=100;
public void run(){
//synchronized (this){
if(total==0)
System.out.println("ERROR, You have not money!");
this.deduct(100);
// }
}
public void deduct (int amount) {
if (total >= amount) {
total -= amount;
}
}
}
public class Main {
public static void main(String[] args) {
Account MrxMrsx = new Account();
Thread Mrx= new Thread(MrxMrsx,"Mrxoperation");
Mrx.start();
Thread Mrsx= new Thread(MrxMrsx,"Mrsxoperation");
Mrsx.start();
}
}
I know this is unlikely that this code doesn’t show ERROR.But it is possible. I want to force this code does not show error.Then I use synchronize and it shows error. How to do that?
I’m not sure what your goal here is, but this code will always result in the error being displayed, synchronized or not.
The synchronized keyword is used for situations where you have two or more instances of the same object in a multi-threaded application where it is possible for more than one object to be in a method, which can result in undefined results.
Consider the following:
public int someMethod() {
/*1*/ int n = 0;
/*2*/ n = someOtherMethod( this.someVariable );
/*3*/ return n;
}
Let’s say you’re writing a multi-threaded application and have two or more instances of an object that contains the proceeding method.
Without synchronization, it is possible for two objects, A & B, to run the code in the following order:
A:1
A:2
B:1
B:2
B:3
A:3
Which will result in object A returning the same result as object B, due to Object B overwriting A’s result in variable n.
By making someMethod synchronized, you force the objects to take turns (one will wait while the other runs the entire method), thereby eliminating the possibility of unexpected results due to concurrent execution of the code.
but this code will always result in the error being displayed, synchronized or not.
Always?! Are you sure?
Let us say that two threads enter this.dudect at the same time.amount is 100 in both threads, and total is 100.Both threads check total >= amount. That is true! So they enter the if block.Now both threads execute: total -= amount; Now total is -100.
Of course this scenario happened unlikely. I want to change that code to more clearly why usage of synchronize is necessary.
Yes, you’re right. If both threads make it past the balance check before the deduction happens, then there will no error displayed.
Writing code that displays a problem due to concurrent access by multiple threads is very tricky because the execution and/or interrupting of threads is determined at runtime by the JVM and not you. Therefore, you might think you’ve succeeded, only to run it again and have nothing go wrong.
If you run the following code a few times, you should get at least one result that shows that Mr doesn’t have enough money, which tells us that Threads don’t always run in the order we expect them to. This is not an example of concurrent execution. Further, with more testing, you’ll notice that it doesn’t matter if the synchronized block is active or not.
class Account implements Runnable {
static int total=100;
String name;
Account( String name ) {
this.name = name;
}
public void run(){
synchronized (this){
if(total==0)
System.out.println("ERROR, " + name + " doesn't have enough money!" );
this.deduct(100);
}
}
public void deduct (int amount) {
if (total >= amount) {
total -= amount;
}
}
}
public class AbalfazlSynch {
public static void main(String[] args) {
new AbalfazlSynch();
}
public AbalfazlSynch() {
for( int i = 0; i < 50; ++i ) {
Account a1 = new Account( "Mr" + i );
new Thread(a1,"Mrxoperation").start();
Account a2 = new Account( "Mrs" + i );
new Thread(a2,"Mrsxoperation").start();
try {
new Thread().sleep( 5 );
} catch ( Exception e ){}
a2.total = 100;
}
}
}
I know I changed the basis of the test, (two threads using the same object) I’ll work on it.
Here we go, when synchronized, it will run through the whole test, when not synchronized, it will show an error.
class Account implements Runnable {
int total = 100;
String name;
Account( String name ) {
this.name = name;
}
public void run(){
synchronized( this ) {
this.deduct( 100 );
}
}
public void deduct (int amount) {
if( total >= amount ) {
methodThatTakesALongTime();
total -= amount;
}
}
private void methodThatTakesALongTime() {
int timewaster = 0;
for( int i = 0; i < 10000; ++i ) {
timewaster += i;
}
}
}
public class AbalfazlSynch {
public static void main(String[] args) {
new AbalfazlSynch();
}
public AbalfazlSynch() {
int loopCount = -1;
int total = -1;
int maxLoops = 10000;
for( int i = 0; i < maxLoops; ++i ) {
Account a1 = new Account( "" + i );
new Thread( a1, "Mrxoperation" ).start();
new Thread( a1, "Mrsxoperation" ).start();
try {
new Thread().sleep( 1 );
} catch ( Exception e ){}
if( a1.total != 0 ) {
loopCount = i;
total = a1.total;
break;
}
// show some life
if( i % (maxLoops / 10) == 0 ) {
System.out.println( ((double)i / (double)maxLoops) * 100 + "% complete" );
}
}
if( total != -1 ) {
System.out.println( "Error: total: " + total + " loop: " + loopCount );
}
System.out.println( "Complete" );
}
}