Solved

static lock

Posted on 2013-01-30
30
317 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
  • 16
  • 12
  • 2
30 Comments
 
LVL 26

Accepted Solution

by:
dpearson earned 400 total points
Comment Utility
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
Comment Utility
so as a result the second lock will block any thread accessing *any* instance of the Test class.

Are you sure, doug?
0
 
LVL 26

Expert Comment

by:dpearson
Comment Utility

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
 
LVL 16

Expert Comment

by:krakatoa
Comment Utility
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
Comment Utility
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 26

Expert Comment

by:dpearson
Comment Utility

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
Comment Utility
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 26

Expert Comment

by:dpearson
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>>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 26

Expert Comment

by:dpearson
Comment Utility

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
Comment Utility
that code will have no impact on anything happening in the other JVM

This is simply not true.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 26

Expert Comment

by:dpearson
Comment Utility

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
Comment Utility
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 26

Expert Comment

by:dpearson
Comment Utility
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
Comment Utility
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 26

Expert Comment

by:dpearson
Comment Utility
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
Comment Utility
So how is it then that FoilTest activates Test's System.out.println() command?
0
 
LVL 26

Expert Comment

by:dpearson
Comment Utility
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
Comment Utility
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 26

Expert Comment

by:dpearson
Comment Utility

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
Comment Utility
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 26

Expert Comment

by:dpearson
Comment Utility
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
Comment Utility
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
Comment Utility
Bill Gates - MSDOS. Tim Berners-Lee - www. Dennis Ritchie - C. Bjarne Soustrup - C++. James Gosling - Java.

krakatoa - 'Pedantic Silliness'.

No topping that.
0
 
LVL 26

Expert Comment

by:dpearson
Comment Utility
Haha - I enjoyed that list :)

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
Comment Utility
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
Introduction Java can be integrated with native programs using an interface called JNI(Java Native Interface). Native programs are programs which can directly run on the processor. JNI is simply a naming and calling convention so that the JVM (Java…
This video teaches viewers about errors in exception handling.
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.

762 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

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now