处理器类-
public class Processor extends Thread {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
private void doJob1() {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + " doing job1");
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " completed job1");
}
}
private void doJob2() {
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + " doing job2");
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " completed job2");
}
}
public void run() {
doJob1();
doJob2();
}
}
主要方法-
final Processor processor1 = new Processor();
final Processor processor2 = new Processor();
processor1.start();
processor2.start();
在第一次运行时,thread-0或thread-1会锁定job1(),而另一个会空闲5秒钟。
在第一个线程释放job1()上的锁并锁定job2()之后,第二个线程将获得job1()上的锁。
我希望第二个线程不应该处于空闲状态,因为job1()被第一个线程锁定,所以它应该先锁定job2(),然后再锁定job1()。
怎么做?
注:这是基本方案。实际上,即使有100个任务和5个线程,我也希望我的代码能够工作。
2条答案
按热度按时间2wnc66cl1#
我想,您正在寻找一种方法来“获取一个锁,如果可能,并做其他事情,如果它不是免费的”。
你可以用
ReentrantLock#tryLock
.方法:
只有在调用时没有被另一个线程持有时才获取锁。
它返回:
true
如果锁是空闲的并且被当前线程获取,或者锁已经被当前线程持有;以及false
否则以下是问题代码的修改版本:
如果第一个任务的锁是空闲的,线程将运行第一个作业
否则它将在第二个之后运行它
Processor.java
:输出示例:
请注意
lock
/tryLock
以及unlock
调用被包围成try
/finally
进入篮子和球:Color.java
:@Data(staticConstructor = "of")
public class Basket {
private final Color color;
// balls that this basket has
private final List balls = new ArrayList<>();
private final Lock lock = new ReentrantLock();
}
`Ball.java`
@Value(staticConstructor = "of")
public class Ball {
Color color;
}
```
Boy.java
每个男孩挑一个球(queue.poll()
)跑到篮下(
baskets.get(color)
(颜色相同)根据篮子被占时的行为,他:
将球扔掉,然后再试一次(可选)
a
(代码中)等待篮子释放(选项
b
)请注意,使用选项
a
对某些人来说这是可能的boy
当另一个扔掉一个ball
而且还没有人捡起它(无论如何,会有人捡起它放进篮子里)最后呢
main
:输出示例:
zed5wv102#
下面是一个稍微复杂一点的示例,其中包含作业的对象和指示作业是否已执行的条件变量,以及 Package 器如何调整
ReentrantLock
一个try with resources语句。几点注意事项
这个
run()
中的方法Processor
现在概括为n个作业的列表。当任何作业尚未执行时,它将尝试执行它们,并在所有作业完成后完成。这个
TryLocker
班级是AutoCloseable
,所以锁定和解锁Job
可以通过在try with resources语句中创建它的示例来完成。这个
Locker
类在这里是未使用的,但它演示了如何对块执行相同的操作lock()
打电话而不是打电话tryLock()
打电话。TryLocker
也可能需要一段时间来调用tryLock
如果愿意的话,在放弃之前等待一段时间;这个修改留给读者作为练习。这个
hasNotRun()
方法Job
只是为了制造anyMatch(Job::hasNotRun)
更具可读性run()
方法Processor
; 它可能没有发挥它的作用,可以不使用。locker类不会使用
Objects.requireNonNull
; 他们通过调用一个方法来立即使用它,所以如果它为null,他们仍然会抛出一个npe,但是放置一个显式的requirennoull可能会使它们更清楚。locker类不必检查是否已经解锁了锁
ReentrantLock
打电话之前unlock()
使它们幂等;他们会扔一个IllegalMonitorStateException
那样的话。在过去,我用一个flag变量对此进行了修改,以避免出现这种情况,但是由于我的意图是在try with resources语句中使用它们,该语句只调用close()
方法一次,我认为如果有人手动调用close方法,最好让它们爆炸。