- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在下面的例子中:
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}
inc1和inc2可以同时访问,但都不能被多线程同时访问。
怎么可能只允许访问 inc1 或 inc2 而另一个就像常规同步一样,但是允许被访问的那个被尽可能多的线程完成。
最佳答案
我认为一个有用的类比是通过十字路口的交通,在那里您可以有多辆汽车共享一条道路,只要它们平行行驶即可。挑战在于为交叉路口找到一种协调策略。
如果流量是间歇性的,@Greg 提出的解决方案可以工作,我们可以等待一个流停止,然后再允许相交的流继续进行。但我怀疑这不太现实。如果一条道路上交通稳定,其余车辆将永远等待,也就是线程饥饿。
另一种策略是让汽车按照先到先得的原则通过,就像在 parking 标志处一样。我们可以使用专用的 semaphore 来实现它对于每个用户获得许可的每个“道路”或路段,首先确保其他路段都没有使用许可:
public class StopSign {
private final Semaphore[] locks;
private volatile int current = 0;
public StopSign(int segments) {
// create and populate lock array, leaving
// all segments drained besides the first
locks = new Semaphore[segments];
Arrays.setAll(locks, i -> new Semaphore(i == 0 ? Integer.MAX_VALUE : 0, true));
}
public void enter(int segment) {
// synchronization is necessary to guard `current`,
// with the added benefit of holding up new threads
// in the active segment while we're gathering permits
synchronized (locks) {
if (segment == current) {
// if our segment is active, acquire a permit
locks[segment].acquireUninterruptibly();
} else {
// otherwise, gather all permits from the active segment
// as they become available and then reclaim our own permits
locks[current].acquireUninterruptibly(Integer.MAX_VALUE);
current = segment;
locks[segment].release(Integer.MAX_VALUE - 1);
}
}
}
public void exit(int segment) {
if (segment != current) {
// we don't own the lock!
throw new IllegalMonitorStateException();
}
locks[segment].release();
}
}
要使用该类,我们只需调用enter(i)
和exit(i)
,其中i
标识道路/路段/我们要使用的方法。这是一个使用 3 个片段的演示:
public static void main(String args[]) {
int segments = 3;
StopSign lock = new StopSign(segments);
IntStream.range(0, segments).parallel().forEach(i -> {
for (int j = 0; j < 10; j++) {
lock.enter(i);
System.out.print(i);
lock.exit(i);
sleepUninterruptibly(20, TimeUnit.MILLISECONDS);
}
});
}
在我的机器上运行测试会产生这种交替模式:
120201210012012210102120021021
如果交通相对较少,此策略可能有意义,但在交通繁忙时,协调每个交叉路口的开销会显着限制吞吐量。对于繁忙的十字路口,您通常需要一个红绿灯,或者可以以合理的频率转移控制权的第三方。这是一个这样的概念的实现,使用管理一组 read/write locks 的后台线程, 确保一次只有一个段有可用的写锁:
public class TrafficLight {
private final ReadWriteLock[] locks;
private final Thread changer;
public TrafficLight(int segments, long changeFrequency, TimeUnit unit) {
// create and populate lock array
locks = new ReadWriteLock[segments];
Arrays.setAll(locks, i -> new ReentrantReadWriteLock(true));
CountDownLatch initialized = new CountDownLatch(1);
changer = new Thread(() -> {
// lock every segment besides the first
for (int i = 1; i < locks.length; i++) {
locks[i].writeLock().lock();
}
initialized.countDown();
int current = 0;
try {
while (true) {
unit.sleep(changeFrequency);
// lock the current segment and cycle to the next
locks[current].writeLock().lock();
current = (current + 1) % locks.length;
locks[current].writeLock().unlock();
}
} catch (InterruptedException e) {}
});
changer.setDaemon(true);
changer.start();
// wait for the locks to be initialized
awaitUninterruptibly(initialized);
}
public void enter(int segment) {
locks[segment].readLock().lock();
}
public void exit(int segment) {
locks[segment].readLock().unlock();
}
public void shutdown() {
changer.interrupt();
}
}
现在让我们调整测试代码:
TrafficLight lock = new TrafficLight(segments, 100, TimeUnit.MILLISECONDS);
结果是一个有序的模式:
000111112222200000111112222200
注意事项:
awaitUninterruptibly()
和 sleepUninterruptibly()
是 Guava helper methods以避免处理 InterruptedException
。随意复制 implementation如果您不想导入库。TrafficLight
可以通过将状态管理委托(delegate)给访问线程来实现,而不是依赖后台线程。这个实现更简单(我认为),但它确实有一些额外的开销,它需要一个 shutdown()
来进行垃圾收集。关于Java - 同步但允许不同线程访问一种方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53784586/
我正在实现 IMAP 客户端,但 IMAP 邮箱同步出现问题。 首先,可以从 IMAP 服务器获取新邮件,但我不知道如何从邮箱中查找已删除的邮件。 我是否应该从服务器获取所有消息并将其与本地数据进行比
我研究线程同步。当我有这个例子时: class A { public synchronized void methodA(){ } public synchronized void met
嗨,我做了一个扩展线程的东西,它添加了一个包含 IP 的对象。然后我创建了该线程的两个实例并启动它们。他们使用相同的列表。 我现在想使用 Synchronized 来阻止并发更新问题。但它不起作用,我
我正在尝试使用 FTP 定期将小数据文件从程序上传到服务器。用户从使用 javascript XMLHttpRequest 函数读取数据的网页访问数据。这一切似乎都有效,但我正在努力解决由 FTP 和
我不知道如何同步下一个代码: javascript: (function() { var s2 = document.createElement('script'); s2.src =
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 7 年前。 Improve this qu
一 点睛 1 Message 在基于 Message 的系统中,每一个 Event 也可以被称为 Message,Message 是对 Event 更高一个层级的抽象,每一个 Message 都有一个
一 点睛 1 Message 在基于 Message 的系统中,每一个 Event 也可以被称为 Message,Message 是对 Event 更高一个层级的抽象,每一个 Message 都有一个
目标:我所追求的是每次在数据库中添加某些内容时(在 $.ajax 到 Submit_to_db.php 之后),从数据库获取数据并刷新 main.php(通过 draw_polygon 更明显)。 所
我有一个重复动画,需要与其他一些 transient 动画同步。重复动画是一条在屏幕上移动 4 秒的扫描线。当它经过下面的图像时,这些图像需要“闪烁”。 闪烁的图像可以根据用户的意愿来来去去和移动。它
我有 b 个块,每个块有 t 个线程。 我可以用 __syncthreads() 同步特定块中的线程。例如 __global__ void aFunction() { for(i=0;i #
我正在使用azure表查询来检索分配给用户的所有错误实体。 此外,我更改了实体的属性以声明该实体处于处理模式。 处理完实体后,我将从表中删除该实体。 当我进行并行测试时,可能会发生查询期间,一个实体已
我想知道 SQLite 是如何实现它的。它基于文件锁定吗?当然,并不是每个访问它的用户都锁定了整个数据库;那效率极低。它是基于多个文件还是仅基于一个大文件? 如果有人能够简要概述一下 sqlite 中
我想post到php,当id EmpAgree1时,然后它的post变量EmpAgree=1;当id为EmpAgree2时,则后置变量EmpAgree=2等。但只是读取i的最后一个值,为什么?以及如何
CUBLAS 文档提到我们在读取标量结果之前需要同步: “此外,少数返回标量结果的函数,例如 amax()、amin、asum()、rotg()、rotmg()、dot() 和 nrm2(),通过引用
我知道下面的代码中缺少一些内容,我的问题是关于 RemoteImplementation 中的同步机制。我还了解到该网站和其他网站上有几个关于 RMI 和同步的问题;我在这里寻找明确的确认/矛盾。 我
我不太确定如何解决这个问题......所以我可能需要几次尝试才能正确回答这个问题。我有一个用于缓存方法结果的注释。我的代码目前是一个私有(private)分支,但我正在处理的部分从这里开始: http
我对 Java 非常失望,因为它不允许以下代码尽可能地并发移动。当没有同步时,两个线程会更频繁地切换,但是当尝试访问同步方法时,在第二个线程获得锁之前以及在第一个线程获得锁之前再次花费太长时间(比如
过去几周我一直在研究java多线程。我了解了synchronized,并理解synchronized避免了多个线程同时访问相同的属性。我编写此代码是为了在同一线程中运行两个线程。 val gate =
我有一个关于 Java 同步的简单问题。 请假设以下代码: public class Test { private String address; private int age;
我是一名优秀的程序员,十分优秀!