使用 CAS 而不是同步
Use CAS instead of synchronized
最近在创建生产可重用实例的工厂时遇到一个情况
public class Factory {
private static final int REUSABLE_TIMES_LIMIT = 10;
private static Product instance = new Product();
private static int getTimes;
public static synchronized Product getInstance() {
if (++getTimes >= REUSABLE_TIMES_LIMIT) {
return nextInstance();
}
return instance;
}
public static synchronized Product nextInstance() {
getTimes = 0;
instance = new Product();
return instance;
}
}
由于getInstance()
和nextInstance()
在我的例子中可能会被不同的线程同时调用,所以我选择在每个线程之前添加synchronized
关键词。然而,synchronized
在很多线程进入该方法时太重了,所以我想根据CAS
重写这个class,即那些class java.util.concurrent.atomic
包。不幸的是,我没有想出一个合适的方法来同时使用两个原子变量,即 instance
和 getTimes
来安排我的代码。有人会告诉我如何在这种情况下正确使用 CAS
而不是 synchronized
而不会导致竞争条件吗?提前致谢:)
一种可能的选择是使用一个 AtomicReference 而不是两个。无论代码复杂度如何,这都会使您的状态保持一致。
public static class ProductStorage {
private Product product;
private int getTimes;
public ProductStorage(Product product, int getTimes) {
this.product = product;
this.getTimes = getTimes;
}
}
public static class Factory {
private static final int REUSABLE_TIMES_LIMIT = 10;
private static AtomicReference<ProductStorage> instance = new AtomicReference<>(
new ProductStorage(new Product(), 0)
);
public static Product getInstance() {
ProductStorage current;
for(;;) {
current = instance.get();
if(current.getTimes >= REUSABLE_TIMES_LIMIT) {
instance.compareAndSet(current, new ProductStorage(new Product(), 0));
continue;
}
if(current.getTimes < REUSABLE_TIMES_LIMIT) {
if(instance.compareAndSet(current, new ProductStorage(current.product, current.getTimes + 1))) {
return current.product;
}
}
}
}
}
您可能会提到的第一件事是在这种情况下总是分配新对象。但请记住,大多数无锁算法都会这样做,这不是问题。 java 中的分配速度很快,只需几纳秒。您可能还会在 Martin Thompson's blog. The code is here 中看到类似的解决方案。在我的机器上,无锁解决方案运行速度快 3-4 倍。
如果可能想要使用两个原子,但这会使计算 getTimes 变得困难。
最近在创建生产可重用实例的工厂时遇到一个情况
public class Factory {
private static final int REUSABLE_TIMES_LIMIT = 10;
private static Product instance = new Product();
private static int getTimes;
public static synchronized Product getInstance() {
if (++getTimes >= REUSABLE_TIMES_LIMIT) {
return nextInstance();
}
return instance;
}
public static synchronized Product nextInstance() {
getTimes = 0;
instance = new Product();
return instance;
}
}
由于getInstance()
和nextInstance()
在我的例子中可能会被不同的线程同时调用,所以我选择在每个线程之前添加synchronized
关键词。然而,synchronized
在很多线程进入该方法时太重了,所以我想根据CAS
重写这个class,即那些class java.util.concurrent.atomic
包。不幸的是,我没有想出一个合适的方法来同时使用两个原子变量,即 instance
和 getTimes
来安排我的代码。有人会告诉我如何在这种情况下正确使用 CAS
而不是 synchronized
而不会导致竞争条件吗?提前致谢:)
一种可能的选择是使用一个 AtomicReference 而不是两个。无论代码复杂度如何,这都会使您的状态保持一致。
public static class ProductStorage {
private Product product;
private int getTimes;
public ProductStorage(Product product, int getTimes) {
this.product = product;
this.getTimes = getTimes;
}
}
public static class Factory {
private static final int REUSABLE_TIMES_LIMIT = 10;
private static AtomicReference<ProductStorage> instance = new AtomicReference<>(
new ProductStorage(new Product(), 0)
);
public static Product getInstance() {
ProductStorage current;
for(;;) {
current = instance.get();
if(current.getTimes >= REUSABLE_TIMES_LIMIT) {
instance.compareAndSet(current, new ProductStorage(new Product(), 0));
continue;
}
if(current.getTimes < REUSABLE_TIMES_LIMIT) {
if(instance.compareAndSet(current, new ProductStorage(current.product, current.getTimes + 1))) {
return current.product;
}
}
}
}
}
您可能会提到的第一件事是在这种情况下总是分配新对象。但请记住,大多数无锁算法都会这样做,这不是问题。 java 中的分配速度很快,只需几纳秒。您可能还会在 Martin Thompson's blog. The code is here 中看到类似的解决方案。在我的机器上,无锁解决方案运行速度快 3-4 倍。
如果可能想要使用两个原子,但这会使计算 getTimes 变得困难。