Reputation: 173
I am trying to learn threading, and regarding the following example
public class LockExample {
private Lock lockone = new ReentrantLock();
public void method1() {
lockone.lock();
try {
// do something
} finally {
lockone.unlock();
}
}
public void method2() {
lockone.lock();
try {
// do something
} finally {
lockone.unlock();
}
}
}
does it mean that if we lock method1
and method2
using the same lock, say thread A
and B
can not access method1
or method2
at the same time. But if we lock method1
and method2
using different locks lockone
and locktwo
, then threadA
can access method1
, at the same time thread B
can access method2
?
why don't we lock each method separately instead of putting them in one lock?
public class LockExample {
private Lock lockone = new ReentrantLock();
public void method1() {
lockone.lock();
try {
// do something
} // wrap the two methods in one lock?
}
public void method2() {
try {
// do something
} finally {
lockone.unlock();
}
}
}
}
Upvotes: 1
Views: 618
Reputation: 27115
why don't we, or can we make method1 and 2 into one critical section by only acquiring the lock in methos1, and releasing the lock after method2?
Because it's bad design.
The office where I work has hundreds of thousands of lines of Java code to maintain. Some of it's been around for as long as ten years, and developers have been coming and going and working in that code all that time. Adherence to strict style rules and strict conventions is an important part of how we keep it all safe and sane and mostly bug-free.
If we use a ReentrantLock, we use always use it just how you used it in your first example:
lockone.lock();
try {
// do something
} finally {
lockone.unlock();
}
If there's a methodOne, and a methodTwo, and there's a need to call them both atomically, then we write it like this:
private methodOne(...) { ... }
private methodTow(...) { ... }
public callMethodOneAndMethodTwo(...) {
lockOneTwo.lock();
try {
methodOne(...);
methodTwo(...);
} finally {
lockOneTwo.unlock();
}
This way of managing the lock guarantees that no thread can ever fail to unlock the lock after it's done what it needs to do. It guarantees that no other function in any other package can call methodOne() without subsequently calling methodTwo(). It guarantees that no such function can call methodTwo() without first calling methodOne(). It's easier to understand, and it's easier to maintain.
Upvotes: 0
Reputation: 3390
does it mean that if we lock method1 and method2 using the same lock, say thread A and B can not access method1 or method2at the same time. But if we lock method1 and method2using different locks lockone and locktwo, then threadA can access method1, at the same time thread Bcan access method2?
Yes, if method1 and method2 using the same lock, then thread A and B cannot access method1 or method 2 at same time. But if methods using different locks, then thread A and B will not be able to access same methods, but accessing different methods will work. That is, thread A and B can't access same method1, or same method2. But while thread A accessing method1, thread B can access method2.
why don't we lock each method separately instead of putting them in one lock?
If you want any threads to block method 2 from accessing, till first thread has not finished access / executtion of method1 and method2, then given code sample is correct.
Example:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main implements Runnable {
private Lock lock = new ReentrantLock();
public void method1() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " entered method1.");
Thread.sleep(1000);
lock.lock();
System.out.println(Thread.currentThread().getName() + " ackquired lock.");
Thread.sleep(1000);
}
public void method2() {
System.out.println(Thread.currentThread().getName() + " entered method2.");
lock.unlock();
System.out.println(Thread.currentThread().getName() + " released lock.");
}
public void run() {
try{
method1();
}catch(Exception e){
e.printStackTrace();
}finally{
method2();
}
}
public static void main(String [] args) {
Runnable runnable = new Main();
new Thread(runnable, "ThreadA").start();
new Thread(runnable, "ThreadB").start();
}
}
Upvotes: 1
Reputation: 36304
If you use the same lock for both methods, then if thread-1 is executing method-1 (i.e, after acquiring the lock), then no other thread can execute method-1 as well as method-2.
If you use 2 different locks for 2 methods, then if thread-1 and thread-2 are executing method-1 and method-2 by acquiring lock on lock-1 and lock-2 respectively, then other threads can execute method-1 if thread-1 releases the lock and method-2 if thread-2 releases the lock.
Upvotes: 0