Solved

Being able to pass a lock between threads?

Posted on 2014-11-19
4
229 Views
Last Modified: 2014-11-24
MCCarl:  This one's for you!  

You suggested the "reentrant lock" in another thread, and I've been looking at it, and it looks like it MIGHT be just what I need.  Here was the code I'd written:  

//Theoretically, this should allow objects to be synchronized across methods and threads instead of just within a single method.
//In practice, this will probably just cause a ton of race conditions and problems.
public class Synchronizer {

	//Track the synchronization of the object manually.
	boolean booLocked = false;
	
	//This is my attempt at a public locking mechanism that will (theoretically) allow thread safety across methods.
	//So if they want to turn the lock "on" first, do the system sync.
	public synchronized void lock() {

		//Now, if the thread is this far, but the boolean shows that the sync is already "on" have the thread wait until it's available.
		while (booLocked) {
			//Allow other threads to run if needed.
			Thread.yield();
		}
		//Theoretically, if we're this far, only one thread should have been permitted to get through the system's "synchronized" function.  So flipping the "locked"
		//to "true" then stepping out of the sync should allow any competing threads to get through one at a time and wait for the boolean to be flipped to "false" again.
		booLocked = true;
 
	}
	
	public void unLock() {
		//Simply flip the switch to unlock.
		booLocked = false;
	}
	
}

Open in new window


The idea would be for me to be able to have an object that can be passed between threads, so that a "lock" on an object would no longer be limited to the method that "synchronized" was called in.  I wrote this code to give me an object that I could pass around like a baton, and only after the CORRECT object called "unlock" could anything be done.  This object that unlocks it, though, might not be in the same thread as the one that locked it.  

Basically, imagine a scenario where I have one thread whose job is to "load and lock" objects, then toss them into a queue.  Other threads will be trying to get at these objects, but will have to wait until they're unlocked.

Another thread picks up any objects in this queue, does some stuff to them, then "unlocks" them, allowing the other threads access to grab and lock them themselves.  

One lock object, used by all threads, but the lock and unlock does not necessarily have to happen within the same thread.  That's the goal behind this code.  

Is this what the ReentrantLock does?  

According to the Oracle docs:  

It is recommended practice to always immediately follow a call to lock with a try block, most typically in a before/after construction such as:

 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Open in new window


This seems to indicate that once again, within the same method, the locks and unlocks should be together.  Am I reading this wrong?
0
Comment
Question by:Javin007
4 Comments
 
LVL 26

Accepted Solution

by:
dpearson earned 500 total points
ID: 40453129
If the goal is to have Thread A lock an object and Thread B unlock it, then I don't think you can use ReentrantLock because only the locking thread can unlock it:

public void unlock()
Attempts to release this lock.
If the current thread is the holder of this lock then the hold count is decremented. If the hold count is now zero then the lock is released. If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

I think instead you maybe want to use a Semaphore
(https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html)

A Semaphore conceptually is more of a set of flags - which you can then use to decide when somebody can do an operation or not.  (You can use a Semaphore to implement the concept of a Lock - they're more primitive than a Lock).  The big difference for you is the "release()" method for a Semaphore is not thread specific:

public void release()
Releases a permit, returning it to the semaphore.
Releases a permit, increasing the number of available permits by one. If any threads are trying to acquire a permit, then one is selected and given the permit that was just released. That thread is (re)enabled for thread scheduling purposes.

There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire(). Correct usage of a semaphore is established by programming convention in the application.

Doug
0
 
LVL 16

Expert Comment

by:krakatoa
ID: 40453266
My name's not mccarl either, but as mentioned before, util.concurrent holds many useful classes, and CyclicBarrier is one you can also read up on.

And "passing a lock" is not only going to be clock-costly, but is not really in the paradigm. Using a thread-superior mechanism that is already in the model is preferable.
0
 
LVL 35

Expert Comment

by:mccarl
ID: 40453998
As Doug has said, it sounds like Semaphore is what you may need, however, I am interested more in your core requirements. You said...

Basically, imagine a scenario where I have one thread whose job is to "load and lock" objects, then toss them into a queue.  Other threads will be trying to get at these objects, but will have to wait until they're unlocked.

Another thread picks up any objects in this queue, does some stuff to them, then "unlocks" them, allowing the other threads access to grab and lock them themselves.  
Now, you may have simplified this a bit just to describe it here, but if this were the actual requirement, could you implement by using 2 queues. The first thread you mention above would load objects onto one queue. Then the last thread that you mention can "...picks up any objects in this queue, does some stuff to them..." BUT then it places them on a 2nd queue. Then these "other threads" can get the objects from the 2nd queue. There is no locking required at all now.

As I said, I'm guessing the actual requirements are more than just this and that may have an impact, so if you can more fully describe what you need, we may be able to provide more assistance.
0
 
LVL 4

Author Closing Comment

by:Javin007
ID: 40462489
Looks like semaphores are the direction I needed to go in. Thanks!
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

INTRODUCTION Working with files is a moderately common task in Java.  For most projects hard coding the file names, using parameters in configuration files, or using command-line arguments is sufficient.   However, when your application has vi…
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:

708 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

17 Experts available now in Live!

Get 1:1 Help Now