admin管理员组文章数量:1279214
What is the best way to achieve following goals? Let's say, given are two synchronized functions func1 and func2
public class xyz {
private Object x1 = new Object();
private boolean isWaiting = false;
public void func1() {
synchronized(this.x) {
if(/*condition1 == expectedvalue*/1 == 1) {
this.isWaiting = true;
this.x1.wait();
}
}
}
public void func2() {
synchronized(this.x1) {
if(this.isWaiting) {
this.x1.notifyAll();
this.isWaiting = false;
}
}
}
}
Now my goal is that when func1 is wait()ing,that it remains NON-REENTRANT for other threads that want to enter it but at same time threads that want to execute func2 are permitted to enter it synchronized on x1 object and notify() waiting function func1 to continue its execution.
My idea was also to create nested Object synchronisation like so
public class xyz {
private Object x1 = new Object();
private Object x2 = new Object();
private boolean isWaiting = false;
public void func1() {
synchronized(this.x2) {
synchronized(this.x1) {
do_here_something_synchronized();
if(/*condition1 == expectedvalue*/1 == 1) {
this.isWaiting = true;
this.x1.wait();
}
}
}
}
public void func2() {
synchronized(this.x1) {
do_here_something_more_synchronized();
if(this.isWaiting) {
this.x1.notifyAll();
this.isWaiting = false;
}
}
}
}
Which would mean in theory that func1 would stop being REENTRANT for other threads when reaching x2 object but at same time func2 would be able to do synchronization work. Nested synchronized blocks are bad practice so far, but is there a better approach to achieve the goals?
Is there a smarter way to implement it, may be as example by java.util.concurrent.locks.* etc. without nesting it inside few synchronized blocks?
I expect some parts of code to be non-reentrant!
What is the best way to achieve following goals? Let's say, given are two synchronized functions func1 and func2
public class xyz {
private Object x1 = new Object();
private boolean isWaiting = false;
public void func1() {
synchronized(this.x) {
if(/*condition1 == expectedvalue*/1 == 1) {
this.isWaiting = true;
this.x1.wait();
}
}
}
public void func2() {
synchronized(this.x1) {
if(this.isWaiting) {
this.x1.notifyAll();
this.isWaiting = false;
}
}
}
}
Now my goal is that when func1 is wait()ing,that it remains NON-REENTRANT for other threads that want to enter it but at same time threads that want to execute func2 are permitted to enter it synchronized on x1 object and notify() waiting function func1 to continue its execution.
My idea was also to create nested Object synchronisation like so
public class xyz {
private Object x1 = new Object();
private Object x2 = new Object();
private boolean isWaiting = false;
public void func1() {
synchronized(this.x2) {
synchronized(this.x1) {
do_here_something_synchronized();
if(/*condition1 == expectedvalue*/1 == 1) {
this.isWaiting = true;
this.x1.wait();
}
}
}
}
public void func2() {
synchronized(this.x1) {
do_here_something_more_synchronized();
if(this.isWaiting) {
this.x1.notifyAll();
this.isWaiting = false;
}
}
}
}
Which would mean in theory that func1 would stop being REENTRANT for other threads when reaching x2 object but at same time func2 would be able to do synchronization work. Nested synchronized blocks are bad practice so far, but is there a better approach to achieve the goals?
Is there a smarter way to implement it, may be as example by java.util.concurrent.locks.* etc. without nesting it inside few synchronized blocks?
I expect some parts of code to be non-reentrant!
Share Improve this question asked Feb 24 at 14:07 sam sussam sus 211 bronze badge1 Answer
Reset to default 0Here's an updated attempt using only ReentrantLock and Conditions
public class Main {
private final ReentrantLock lock = new ReentrantLock();
private final Condition reentrantBlocker = lock.newCondition();
private final Condition notifyContinue = lock.newCondition();
public void waitingThread() {
lock.lock();
try {
if (lock.getWaitQueueLength(notifyContinue) > 0) { //if the first time calling, should not be blocked
System.out.println(Thread.currentThread().getName() + " wait queue for reentrant blocker: " + (lock.getWaitQueueLength(reentrantBlocker) + 1)); //wait queue including "my" wait
System.out.println(Thread.currentThread().getName() + " awaiting on reentrant blocker");
reentrantBlocker.await(); // Blocks reentrant by other threads and gives up lock
}
do_something();
System.out.println(Thread.currentThread().getName() + " await continue");
this.notifyContinue.await(); //wait to be notified to continue
System.out.println(Thread.currentThread().getName() + " signal reentrant blocker");
this.reentrantBlocker.signal(); //signals one other thread waiting for reentrant to continue
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public void notifyingThread() {
lock.lock();
try {
if (lock.getWaitQueueLength(notifyContinue) > 0) {
do_something_else();
System.out.println(Thread.currentThread().getName() + " signal continue");
notifyContinue.signal(); // Notify waiting thread
} else {
System.out.println(Thread.currentThread().getName() + " do not do something else if no one is waiting for it");
}
} finally {
lock.unlock();
}
}
public void do_something() {
System.out.println(Thread.currentThread().getName() + " do_something");
}
public void do_something_else() {
System.out.println(Thread.currentThread().getName() + " do_something_else");
}
public static void main(String[] args) throws InterruptedException {
Main m = new Main();
var service = Executors.newFixedThreadPool(8);
for (int i = 0; i < 4; i++) {
Thread.sleep(2000);
service.submit(m::notifyingThread);
}
for (int i = 0; i < 4; i++) {
service.submit(m::waitingThread);
}
Thread.sleep(2000);
for (int i = 0; i < 4; i++) {
Thread.sleep(2000);
service.submit(m::notifyingThread);
}
service.shutdown();
service.awaitTermination(15, TimeUnit.SECONDS);
}
}
This gives the output as follows:
pool-1-thread-1 do not do something else if no one is waiting for it
pool-1-thread-2 do not do something else if no one is waiting for it
pool-1-thread-3 do not do something else if no one is waiting for it
pool-1-thread-4 do not do something else if no one is waiting for it
pool-1-thread-5 do_something
pool-1-thread-5 await continue
pool-1-thread-6 wait queue for reentrant blocker: 1
pool-1-thread-6 awaiting on reentrant blocker
pool-1-thread-7 wait queue for reentrant blocker: 2
pool-1-thread-7 awaiting on reentrant blocker
pool-1-thread-8 wait queue for reentrant blocker: 3
pool-1-thread-8 awaiting on reentrant blocker
pool-1-thread-1 do_something_else
pool-1-thread-1 signal continue
pool-1-thread-5 signal reentrant blocker
pool-1-thread-6 do_something
pool-1-thread-6 await continue
pool-1-thread-2 do_something_else
pool-1-thread-2 signal continue
pool-1-thread-6 signal reentrant blocker
pool-1-thread-7 do_something
pool-1-thread-7 await continue
pool-1-thread-3 do_something_else
pool-1-thread-3 signal continue
pool-1-thread-7 signal reentrant blocker
pool-1-thread-8 do_something
pool-1-thread-8 await continue
pool-1-thread-4 do_something_else
pool-1-thread-4 signal continue
pool-1-thread-8 signal reentrant blocker
You can probably reference this as inspiration for however you want to structure your solution.
本文标签:
版权声明:本文标题:java - Stop reentrant synchronization only for specified function (or code) while waiting but permit reentrant synchronizing in 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741265267a2368342.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论