如何在多线程环境中设置值时删除双重检查
How to remove double checking when setting a value in a multithreaded environment
我有一个 class Checker
存储字段 archiveDate
。有几个线程可以设置这个字段。他们仅在该字段尚不可用时才记录该字段。如果其中一个线程记录了日期,则其他线程不必覆盖它。还有另一个线程(Checker
本身)可以删除日期。它仅在设置日期后删除日期。现在我的代码看起来像这样。
public class Checker extends Thread {
private volatile LocalDateTime archiveDate;
private ReentrantLock lock;
public Checker() {
lock = new ReentrantLock();
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
if (archiveDate != null) {
lock.lock();
try {
if (archiveDate != null && archiveDate.isBefore(LocalDateTime.now())) {
//do something
archiveDate = null;
}
} finally {
lock.unlock();
}
}
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
public void changeDate(LocalDateTime date) {
if (archiveDate == null) {
lock.lock();
if (archiveDate == null) {
try {
archiveDate = date;
} finally {
lock.unlock();
}
}
}
}
}
我可以避免双重检查或以某种方式简化代码吗?
在我看来,您使用的工具不正确。要在特定日期时间执行任务,请使用 ScheduledExecutorService
:
的适配器
static final ScheduledExecutorService ES = Executors.newSingleThreadScheduledExecutor();
public static ScheduledFuture<?> schedule(LocalDateTime targetTime, Runnable r) {
return ES.schedule(r,
LocalDateTime.now().until(targetTime, ChronoUnit.NANOS), TimeUnit.NANOSECONDS);
}
对我来说,不管指定的日期如何,在有待处理的请求时忽略新请求看起来有点奇怪,但是可以使用上面的 schedule
方法实现与您的问题代码类似的逻辑:
class Checker implements Runnable {
final AtomicReference<LocalDateTime> archiveDate = new AtomicReference<>();
@Override
public void run() {
//do something
archiveDate.set(null);
}
public void changeDate(LocalDateTime date) {
if(archiveDate.compareAndSet(null, date)) {
schedule(date, this);
}
}
}
我有一个 class Checker
存储字段 archiveDate
。有几个线程可以设置这个字段。他们仅在该字段尚不可用时才记录该字段。如果其中一个线程记录了日期,则其他线程不必覆盖它。还有另一个线程(Checker
本身)可以删除日期。它仅在设置日期后删除日期。现在我的代码看起来像这样。
public class Checker extends Thread {
private volatile LocalDateTime archiveDate;
private ReentrantLock lock;
public Checker() {
lock = new ReentrantLock();
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
if (archiveDate != null) {
lock.lock();
try {
if (archiveDate != null && archiveDate.isBefore(LocalDateTime.now())) {
//do something
archiveDate = null;
}
} finally {
lock.unlock();
}
}
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
public void changeDate(LocalDateTime date) {
if (archiveDate == null) {
lock.lock();
if (archiveDate == null) {
try {
archiveDate = date;
} finally {
lock.unlock();
}
}
}
}
}
我可以避免双重检查或以某种方式简化代码吗?
在我看来,您使用的工具不正确。要在特定日期时间执行任务,请使用 ScheduledExecutorService
:
static final ScheduledExecutorService ES = Executors.newSingleThreadScheduledExecutor();
public static ScheduledFuture<?> schedule(LocalDateTime targetTime, Runnable r) {
return ES.schedule(r,
LocalDateTime.now().until(targetTime, ChronoUnit.NANOS), TimeUnit.NANOSECONDS);
}
对我来说,不管指定的日期如何,在有待处理的请求时忽略新请求看起来有点奇怪,但是可以使用上面的 schedule
方法实现与您的问题代码类似的逻辑:
class Checker implements Runnable {
final AtomicReference<LocalDateTime> archiveDate = new AtomicReference<>();
@Override
public void run() {
//do something
archiveDate.set(null);
}
public void changeDate(LocalDateTime date) {
if(archiveDate.compareAndSet(null, date)) {
schedule(date, this);
}
}
}