Solved

static lock

Posted on 2013-01-30
30
329 Views
Last Modified: 2013-02-04
hi guys
I need some clarification on using static lock.
Lets say i have this code

public class Test {
private final Object someObject = new Object();
public void doSomething()
{
	synchronized (someObject) {
		System.out.println(someObject.toString());
	}
}

}

Open in new window


How is the above code different from

public class Test {
private static final Object someObject = new Object();
public void doSomething()
{
	synchronized (someObject) {
		System.out.println(someObject.toString());
	}
}

Open in new window


any answers in laymans terms with an example will be greatly apprecaited
thanks
0
Comment
Question by:royjayd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 16
  • 12
  • 2
30 Comments
 
LVL 27

Accepted Solution

by:
dpearson earned 400 total points
ID: 38838473
The difference is that this object:
private static final Object someObject = new Object();

is shared by all members of the class Test, so as a result the second lock will block any thread accessing *any* instance of the Test class.

Since the first lock is using an instance object:
private final Object someObject = new Object();

the lock will only block threads if they are accessing the same instance of Test.

In more practical terms, if you have a class that has no static members (which is typical) then you only need the first type of lock to correctly protect it from multiple threads.  If you use the second type of lock your code will run more slowly than it needs to (assuming the class has no static data members).

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38840454
so as a result the second lock will block any thread accessing *any* instance of the Test class.

Are you sure, doug?
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38842805

so as a result the second lock will block any thread accessing *any* instance of the Test class.
Are you sure, doug?

Yes pretty sure.  Locks are based around a specific object - in this case "someObject".  The question is what's the scope of that object.

A static member is shared by all instances of a class, so if one thread holds that shared object no other thread can advance through that same lock.

An instance member however is not shared - there's one for each instance of the parent class, so a thread that has locked a particular instance will have no effect on others instances because they are locked on different "someObject" instances.

Both forms can be useful - you just need to know what they're doing.  As I mentioned, the first form is more commonly useful, but there are definitely situations (e.g. when working with a singleton) where you'd want the second form.

Doug
0
Revamp Your Training Process

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action.

 
LVL 16

Expert Comment

by:krakatoa
ID: 38843156
It looks to me as though only the System.out.println() routine has a lock on it. "someObject" doesn't, nor does the class, nor the method containing the locked routine. cf : Intrinsic Locks

And in the first code example I can't see the point of locking, since someObject is private anyway.
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38843273
Crude examples with some adjustments to show that a synched statement block inside a method does not block that method call and execution if there are other legitimately accessible parts of the method without locks. The "Test.class" code prints its ID once, then perpetually holds inside the synched routine, to allow "FoilTest.class" to call another part of the method.

public class Test {
private static final Object someObject = new Object();
public static Test t;
private static int doSomethingCalls = 0;
public static void doSomething(String classStringID)
{
	synchronized (someObject) {
		if((classStringID.equals(someObject.toString()))){
		   System.out.println(someObject.toString());

		   while(true){try{Thread.sleep(2000);}catch(InterruptedException u){}Thread.yield();}
		}
	}

	if(!(classStringID.equals(someObject.toString()))){
	    System.out.println("Received instruction to print from another class.");
	    doSomethingCalls++;
	   System.out.println("Number of times doSomething has been called = "+doSomethingCalls);
	}
}

public static void main(String[] args){


	while(true){
	 t = new Test();
	  t.doSomething(someObject.toString());
	   try{Thread.sleep(2000);}catch(InterruptedException e){}
	}
}

}

Open in new window


"FoilTest"

public class FoilTest {
private static final Object someObject = new Object();

public static void main(String[] args){


	
	while(true){
	   new FoilTest().interfere();
	   try{Thread.sleep(2000);}catch(InterruptedException e){}
	}
}

void interfere(){

Test.doSomething(someObject.toString());

}

}

Open in new window

0
 
LVL 27

Expert Comment

by:dpearson
ID: 38844593

Crude examples with some adjustments to show that a synched statement block inside a method does not block that method call and execution if there are other legitimately accessible parts of the method without locks.

Yes this is absolutely correct.  Synchronized statements only control access to the block they surround.  Anything not inside a synchronized statement is certainly free to execute.

When I said the 2nd form blocks access to all instances of the class - I mean more specifically "any method that uses synchronized(someObject) { } to control multithreaded access will be blocked by any call on any instance of this class to any method that is also using synchronized(someObject) {} to control access to the method, when someObject is a static instance".

Also the original code is clearly just test code - there's no need to do the synchronization.  He's just exploring what the behavior is for the different variable scopes.

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38844712
Let's say that this :

synchronized (someObject) {

		
		if(classStringID.equals(someObject.toString())){
		   System.out.println(someObject.toString());
		
		   while(true){;}//{try{Thread.sleep(2000);}catch(InterruptedException u){}}
		}
		
		if(!(classStringID.equals(someObject.toString()))){
			System.out.println(" WHAT WOULD YOU SAY HERE ? ");
		}

	}

Open in new window


is the synched part of the doSomething method. What would you expect to happen when doSomething is called from a "FoilTest" class instance?
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38844912
FoilTest and Test both have main methods - so it looks like they're intended to be run as separate processes - in which case they are in different JVMs and won't interact at all.  Each of Test and FoilTest also appear to be single threaded themselves.

If you wish to test this you need multiple threads running inside the same JVM.

If you had that, then there will only ever be one thread executing code inside a synchronized(someObject) { } code block where someObject is defined as:
private static final Object someObject = new Object();

The lock will only apply to the code block, i.e. the stuff inside the { } after the synchronized statement.  It's not locking the method or any higher level concept.  (That's just how synchronized works).

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38845001
If you run these classes - from separate JVMs - FoilTest accesses Test's doSomething method, as its static. In fact, you don't even have to have Test class running - this is what static modifiers allow you to do. (That's what "calling on the class" means).

That was not my question however, although we'd better clear this present point up first about what needs to be running and where before we go back to that.
0
 

Author Comment

by:royjayd
ID: 38845018
you couldnt have explained it any better Doug.

>>>If you wish to test this you need multiple threads running inside the same JVM.

Do you have an example i can test.

Thanks.
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38845054
you couldnt have explained it any better Doug.

How is it you feel you can pronounce on a situation that you originally didn't understand all of a sudden? Have you thought through the implications of my last post?
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38845141
You see you said this earlier :

>>is shared by all members of the class Test, so as a result the second lock will block any thread accessing *any* instance of the Test class.

Which isn't true, afaict.
0
 

Author Comment

by:royjayd
ID: 38845223
>>Which isn't true, afaict
so what are you saying ?

Are you saying that the static lock in this case
private static final Object someObject = new Object();

is not shared across all the objects of class Test ?
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38845294

Are you saying that the static lock in this case
private static final Object someObject = new Object();

is not shared across all the objects of class Test ?

No it is shared across all the objects - as long as your code is executing in the same JVM :)

I think you've got this well understood now royjayd.

Just as final clarification - all consideration of threads is within a single JVM.  If you start a separate process (a separate JVM) that code will have no impact on anything happening in the other JVM.  It can be executing the same Java code - but each JVM has completely independent memory spaces (so a static variable will exist once in each JVM).  If you lock it in one JVM it will have no impact on anything happening in another JVM.

Anyway I think we've satisfied the original question here :)

krakatoa if you want to start a new thread on the details of the difference between threads, processes and address spaces I'd be very happy to chip in on that.  But I think we're pretty well off topic from the original post.

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38845453
that code will have no impact on anything happening in the other JVM

This is simply not true.
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38845531

that code will have no impact on anything happening in the other JVM

This is simply not true.

No really it is :)  We're getting more into OS theory now, but each JVM is a separate process with its own virtual memory space and one of the things any modern OS enforces is that one process cannot directly address the memory of another process.

If you go back far enough in time (e.g. Windows 95) that wasn't always true - which is why those machines were so easy to crash.  But since the days of Windows XP or Linux or Mac OS 10 each process has a completely separate address space.

The only way to communicate between them would be via a socket or a shared memory space (like a shared memory file).  Certainly a lock or static class variable doesn't interact.

(Trust me - we run multiple JVMs on a single physical box all the time, each running thousands of threads and those threads don't collide with each other).

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38845568
The two classes I posted - if you run them in separate JVMs, you will see that FoilTest calls the doSomething method in Test. And it runs. What have I misunderstood  . . . ?

>> those threads don't collide

This has nothing to do with "collisions" - whatever you mean by that.
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38846185
Hi krakatoa,

I'll take one more crack at this.  Sorry my explanations are leaving you so confused.

Two processes can both execute the same set of instructions at the same time (e.g. you can have two instances of Microsoft Word running at the same time or two copies of notepad running).  But each has a completely separate memory area that they use.  There's nothing that happens in the first process that will interact in any way with the second process (unless you work hard - e.g. opening up a socket or writing a file to disk).

A thread is a smaller entity than a process and exist within the memory space of the parent process.  If you have 2 threads in process A, they can interact with each other (e.g. colliding on trying to obtain a synchronization lock, causing one thread to wait for the other).  However, they cannot interact with any threads executing in process B.

So in your case you have two programs (processes) which are running the same code - calling to a shared Test class.  But the only thing they share is the code - the instructions.  The value of the variables, what threads are running, which locks exist etc. don't affect each other, so certainly they both run.

The original question was about when will 2 threads interact with each and when not.  In this case they will interact when:
a) both threads are in the same process (program/JVM - all mean the same thing here)
b) if the locked object (someObject) is static, they will always interact with each other if they call any method on *any* instance of the Test class (that uses this sort of synchronization lock and remember is in the same process/JVM)
c) if the locked object (someObject) is not static, they will only interact with each other if they call a method on the *same* instance of the Test class (that uses this sort of synchronization lock).

It's a tricky thing to get a full understanding of all this - there's a lot of concepts involved here.  I hope this helps.  If not I think we'll just have to agree to let it rest.

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38846487
There is less confusion on my part than you think. I understand what separate programme instances are. What I don't comprehend is why you have not answered my previous point that I have made more than once, as to whether doing this :

java Test

and

java FoilTest

*in separate Command Prompts*, means that 2 JVMs are running. AFAIK, it does mean that 2 are invoked. We can't really let this rest until at least this point is resolved, because it's important for others reading this thread if no other reason. Thanks.
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38847131
Yes - each command at the command prompt starts a new process, so

java Test

and

java FoilTest

will start 2 processes, which in Java's case means 2 JVMs which will then not interact with each other (a synchronized lock held in one won't affect any kind of synchronized lock in the other no matter what object it's on).
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38847326
So how is it then that FoilTest activates Test's System.out.println() command?
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38847390
Both FoilTest and Test can call to the same code - they're sharing code (instructions) but not data (memory).

Perhaps a simpler example would make this clearer?
public class Shared {
    public static String someObject = "shared" ;
    
    public static void doSomething(String value) {
         synchronized(someObject) {    // This synchronize statement is doing nothing in this case
             someObject = value ;
             System.out.println(someObject) ;
         }
    }
}

public class Test1 {
    public static void main(String[] args) {
        Shared.doSomething("test1") ; // Will print "test1"
    }
}

public class Test2 {
    public static void main(String[] args) {
        Shared.doSomething("test2") ; // Will print "test2"
    }
}

Open in new window


Now you can run "java Test1" and "java Test2" and both will use the Shared class, but print different values.
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38847459
Well, your examples are no different to those I already gave - they do the same thing. The upshot is a contradiction in terms to what you were first saying, which is the complete opposite.

>>the second lock will block any thread accessing *any* instance of the Test class.<<
 (Where "test" in this case you have now renamed to "Shared", adding to the confusion.

The point again is that the classes (objects in different JVMs) can talk to each other as I keep saying. My FoilTest class passes its own toString() value to Test, and Test will obligingly print it. Why are you having such difficulty with this?

And this :

(a synchronized lock held in one won't affect any kind of synchronized lock in the other no matter what object it's on).

I never said was true, nor implied, thought nor suggested.
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38847968

The point again is that the classes (objects in different JVMs) can talk to each other as I keep saying. My FoilTest class passes its own toString() value to Test, and Test will obligingly print it. Why are you having such difficulty with this?

I think you're maybe confusing classes and JVMs.  FoilTest can pass data to Test - but that's because in that case the Test class has been loaded into the same JVM as FoilTest.

Lets go back to your original setup:
a) Run "java FoilTest" starts a JVM.  This JVM contains the classes FoilTest *and* Test.  Data can happily be shared among these classes as normal in any Java program but that's all inside the same JVM.  Test here is not in a different JVM.

b) Run "java Test" starts a second JVM.  This JVM contains the Test class.

There's no communication between the JVMs.  There are 2 copies of the Test class (the code), one in each of the JVMs.  Those two copies can't communicate with each other.  The FoilTest class is only communicating with the copy of Test that is within its same process (JVM).

So now to go back to my original statement:
>>the second lock will block any thread accessing *any* instance of the Test class.<<

the only clarification perhaps needed here is:
>>the second lock will block any thread accessing *any* instance of the Test class from within the same JVM.  Anything happening in a different JVM has no impact on this at all or anything else going on in the first JVM.<<

Are we on the same page?
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38849370
If you want to communicate between JVMs :

import java.io.*;

public class Test {

static FileReader fr;

	public static void main(String[] args){
 		File file = new File("A_File_Of_Your_Choice.txt");
		try{
		FileWriter fw = new FileWriter(file,false);
		fr =new FileReader(file);
		fw.write("g");
		fw.close();
		
		}catch(Exception e){}
	
	try{
	char c;
	while((c=((char)fr.read()))=='g'){
		 fr.close();
		fr =new FileReader(file);
	   try{Thread.sleep(2000);}catch(InterruptedException e){}
		
	   System.out.println("Test still running");
	
	}
	}catch(Exception excc){}
}

}

Open in new window


then run this after a while in another JVM

import java.io.*;

public class FoilTest {


	public static void main(String[] args){

	
		File file = new File("A_File_Of_Your_Choice.txt");
		try{
		FileWriter fw = new FileWriter(file,false);

		fw.write("s");
		fw.close();
		}catch(Exception e){}
	}
}

Open in new window

0
 
LVL 27

Expert Comment

by:dpearson
ID: 38849532
Haha - you really took the time to point out that the file system is a shared resource?

I think we've reached pedantic silliness now.

I also think we're officially finished on the original topic of the scope of synchronized locks.  Sorry royjayd for veering so off topic - but in among all this I think we got your original question answered.

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38849585
No Sockets in sight. Different JVMs. You said it wasn't possible. The end user doesn't really care what happens inside the black box anyway.
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38851770
Bill Gates - MSDOS. Tim Berners-Lee - www. Dennis Ritchie - C. Bjarne Soustrup - C++. James Gosling - Java.

krakatoa - 'Pedantic Silliness'.

No topping that.
0
 
LVL 27

Expert Comment

by:dpearson
ID: 38851910
Haha - I enjoyed that list :)

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 38851975
Good.

I am of neolithic simplicity; but despite that, my dearly-held metaview is this : if it squeals like a pig and snorts like one, then . . . My file write/read legeredemain was only meant to be as an end-user's (I include myself in that category) perspective of a final result - how that result is arrived at (even in a technically non-kosher fashion) pales into insignificance should it issue in an effective outcome! ;)

:)
0

Featured Post

Creating Instructional Tutorials  

For Any Use & On Any Platform

Contextual Guidance at the moment of need helps your employees/users adopt software o& achieve even the most complex tasks instantly. Boost knowledge retention, software adoption & employee engagement with easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Viewers learn about the “while” loop and how to utilize it correctly in Java. Additionally, viewers begin exploring how to include conditional statements within a while loop and avoid an endless loop. Define While Loop: Basic Example: Explanatio…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question