通常可以从多个线程访问资源(读/写逻辑稍微复杂但不是问题的主题)。我必须创建一个方法owned
,它使调用线程成为资源的所有者,并创建另一个方法notOwned
,使所有线程都可以再次访问该资源。因此,在owned
期间,只有调用线程才能接受资源,直到调用notOwned
为止。
public class Example {
public HashMap<String, Stuff> resources;
public final ReentrantLock lock = new ReentrantLock();
.....
public void owned(String resource) {
// TODO Auto-generated method stub
resources.get(resource).lock.lock();
}
public void notOwned(String resource) {
// TODO Auto-generated method stub
resources.get(resource).lock.unlock();
}
public void operation(String resource) {
//the resource may or may be not owned (it is not owned all the time, as I said)
boolean own = true;
while (own) {
own = ((resources.get(resource).lock.isHeldByCurrentThread() == false) && (resources.get(resource).lock.isLocked()));
}
//so now the resource is :
//1. no longer owned, so all the threads can use it or
//2. the current thread is the owner
try {
//let's consider this operation a writing type
resources.get(resource).readLock.lock();
tables.get(resources).information.add(resource);
} finally {resources.get(resource).readLock.unlock(); }
}
等待资源不再被线程锁定是我提出的唯一解决方案......但是不一致(意味着我想某些资源被锁定时,其他线程(所以不是所有者线程)仍在进行更改或者可能没有正确同步?我真的不知道)...它不一定是ReentrantLock但是必须围绕{{1}创建逻辑}和owned
方法。
答案 0 :(得分:0)
在Java中,线程在尝试获取监视器不可用(已锁定)的对象上的监视器(内部锁定对象)时进入等待状态。解锁此监视器后,将通知此监视器对象上等待的所有线程。这些线程为监视器完成,其中一个线程将再次获取监视器,其他线程将进入WAIT状态。
请根据您的代码查看以下示例,这是使用锁的正确方法。
public class Stuff {
public final ReentrantLock resourceLock = new ReentrantLock();
public void doStuff() {
/*Once locked by one thread other threads would be waiting on this line in WAIT state
* There's no need to check if it's already locked or not, it's done by Java, if it's locked then Thread goes in WAIT state
* It's not busy waiting, thread wakes up only when notified by Java.
*/
resourceLock.lock();
try {
/* <Critical Section> */
//Now since resource is locked, it can be exclusively used by this thread
/* </Critical Section> */
} finally {
//Once unlocked other threads would compete to acquire lock on: resourceLock.lock();
resourceLock.unlock();
}
}
}
public class Example {
public HashMap<String, Stuff> resources;
/**
* This is a utility method to just check if the resource is locked by current Thread, it performs no role in locking resource.
*/
public boolean isOwned(String resource) {
return ((resources.get(resource).lock.isHeldByCurrentThread() == false) && (resources.get(resource).lock.isLocked()))
}
public boolean isNotOwned(String resource) {
return !isOwned();
}
public void operation(String resource) {
Stuff stuff = resources.get(resource);
stuff.doStuff();
}
}
关于WAIT状态的一些有趣的事情
编辑:对于临时临界区,可以动态设置并行或非并行
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
class Stuff {
public final ReentrantLock lock = new ReentrantLock();
public AtomicBoolean isParallel = new AtomicBoolean(true);
public AtomicInteger currentlyRunningThreadCount = new AtomicInteger();
public CountDownLatch latch;
public final static int MAX_WAIT_IN_SECONDS = 20;
public void doStuff() throws Exception {
if( !isParallel.get()) {
System.out.println(threadName() + " Waiting");
synchronized(this) {
if(latch == null) {
latch = new CountDownLatch(currentlyRunningThreadCount.get());/*Excluding the current thread with -1*/
System.out.println("latch count : " + latch.getCount() + " " + latch);
}
}
latch.await(MAX_WAIT_IN_SECONDS, TimeUnit.SECONDS);
if( !lock.tryLock(MAX_WAIT_IN_SECONDS, TimeUnit.SECONDS)) {
throw new Exception("Could not acquire lock in specified time");
}
currentlyRunningThreadCount.incrementAndGet();
System.out.println(threadName() + " Woke up");
}
try {
/* <Critical Section> */
for(int i = 0; i < 3; i++) {
System.out.println(threadName() + " \tRunning");
Thread.sleep(2000);
}
/* </Critical Section> */
} finally {
if(currentlyRunningThreadCount.get() > 0) {
currentlyRunningThreadCount.decrementAndGet();
}
if( !isParallel.get() && latch != null) {
latch.countDown();
System.out.println(threadName() + " down latch " + latch.getCount() + " " + latch);
}
if(lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
System.out.println(threadName() + " Done do stuff");
}
public boolean isParallel() {
return isParallel.get();
}
public void setParallel(boolean newValue) throws Exception {
synchronized(this) {
if(latch != null) {
latch.await();
}
latch = null;
}
isParallel.set(newValue);
}
public String threadName() {
return Thread.currentThread().getName();
}
}
public class Example {
public static void main(String[] args) throws Exception {
System.out.println("Started");
Stuff stuff = new Stuff();
Runnable run = () -> {
try {
stuff.doStuff();
} catch (Exception e) {
e.printStackTrace();
}
};
Thread t1 = new Thread(null, run, "t1");
t1.start();
Thread t2 = new Thread(null, run, "t2");
t2.start();
Thread.sleep(2000);
stuff.setParallel(false);
Thread t5 = new Thread(null, run, "t5");
t5.start();
Thread t6 = new Thread(null, run, "t6");
t6.start();
System.out.println("##### main exiting");
}
}
Started
t1 Running
t2 Running
t1 Running
t2 Running
t5 Waiting
latch count : 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
##### main exiting
t6 Waiting
t5 Woke up
t5 Running
t2 Running
t1 Running
t5 Running
t2 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
t2 Done do stuff
t1 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
t1 Done do stuff
t5 Running
t5 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
t5 Done do stuff
t6 Woke up
t6 Running
t6 Running
t6 Running
t6 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
t6 Done do stuff