我应该使用原子整数还是同步
Should I use atomic integer or sync
我对在我的代码中使用 atomic/volatile/sync 有点困惑。
假设我在一家书店有一个图书信息对象,例如,可能会发生两个线程想要拿走同一本书,而库存中的数量只有 1,我怎么能保证只有一个线程会拿走这本书?
我必须使用同步吗?
图书库存信息:
package bgu.spl.mics.application.passiveObjects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Passive data-object representing a information about a certain book in the inventory.
*
* <p>
*
*/
public class BookInventoryInfo {
//The title of the book, his amount in the inventory and the price
private String bookTitle;
private AtomicInteger amountInInventory;
private int price;
public BookInventoryInfo(String bookTitle, int amountInInventory, int price) {
this.bookTitle = bookTitle;
this.price = price;
this.amountInInventory = new AtomicInteger(amountInInventory);
}
/**
* Retrieves the title of this book.
* <p>
* @return The title of this book.
*/
public String getBookTitle() {
return this.bookTitle;
}
/**
* Retrieves the amount of books of this type in the inventory.
* <p>
* @return amount of available books.
*/
public int getAmountInInventory() {
return this.amountInInventory.get();
}
/**
* Retrieves the price for book.
* <p>
* @return the price of the book.
*/
public int getPrice() {
return this.price;
}
public void reduceAmountInInventory() {
this.amountInInventory.decrementAndGet();
}
}
我想要的取书方式:
if(book.getAmountInInventory > 0)
{
book.amountInInventory--
}
您应该使用 synchronized
,因为使用 AtomicInteger 并不像乍看起来那么简单。虽然 AtomicInteger 上的单个操作是线程安全的,但使用多个操作可能不是。你的例子很好。说你有
// say it start at 1
Thread1: if(book.getAmountInInventory > 0)
Thread2: if(book.getAmountInInventory > 0)
Thread1: book.amountInInventory--
Thread2: book.amountInInventory--
金额现在是-1。
如果你使用synchronized
,那么在整个操作中持有锁会简单得多
synchronized (book) {
if(book.getAmountInInventory > 0) // no chance for a race condition here.
{
book.amountInInventory--
}
这里 AtomicInteger
是不够的。虽然它允许您以原子方式减少库存中的副本数量,但这还不够——您不需要仅以原子方式减少它,您还需要添加一些自定义逻辑。
我会使用普通的旧 int
,并使用显式 synchronized
块或方法保护其修改:
public class BookInventoryInfo {
private String bookTitle;
private int amountInInventory;
private int price;
public synchronized void checkOut() {
if (amountInInventory <= 0) {
throw new BookCheckoutException("No book in inventory");
}
amountInInventory--;
}
// All the other methods...
}
作为同步的替代方法,您还可以使用 compareAndSet
:
int a = book.amountInventory.get();
if (a > 0) {
boolean updated = book.amountInInventory.compareAndSet(a, a - 1);
}
这将只减少amountInInventory
的值,如果它的值仍然是a
,当你来更新它时。 compareAndSet
的 return 值表示该值是否已更改。
您可以将其包装在一个循环中,例如:
while (true) {
int a = book.amountInventory.get();
if (a == 0) {
return false; // To mean "no book in inventory";
}
if (book.amountInInventory.compareAndSet(a, a - 1)) {
return true; // To mean "there was a book in inventory, and it was removed".
}
}
我对在我的代码中使用 atomic/volatile/sync 有点困惑。 假设我在一家书店有一个图书信息对象,例如,可能会发生两个线程想要拿走同一本书,而库存中的数量只有 1,我怎么能保证只有一个线程会拿走这本书? 我必须使用同步吗? 图书库存信息:
package bgu.spl.mics.application.passiveObjects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Passive data-object representing a information about a certain book in the inventory.
*
* <p>
*
*/
public class BookInventoryInfo {
//The title of the book, his amount in the inventory and the price
private String bookTitle;
private AtomicInteger amountInInventory;
private int price;
public BookInventoryInfo(String bookTitle, int amountInInventory, int price) {
this.bookTitle = bookTitle;
this.price = price;
this.amountInInventory = new AtomicInteger(amountInInventory);
}
/**
* Retrieves the title of this book.
* <p>
* @return The title of this book.
*/
public String getBookTitle() {
return this.bookTitle;
}
/**
* Retrieves the amount of books of this type in the inventory.
* <p>
* @return amount of available books.
*/
public int getAmountInInventory() {
return this.amountInInventory.get();
}
/**
* Retrieves the price for book.
* <p>
* @return the price of the book.
*/
public int getPrice() {
return this.price;
}
public void reduceAmountInInventory() {
this.amountInInventory.decrementAndGet();
}
}
我想要的取书方式:
if(book.getAmountInInventory > 0)
{
book.amountInInventory--
}
您应该使用 synchronized
,因为使用 AtomicInteger 并不像乍看起来那么简单。虽然 AtomicInteger 上的单个操作是线程安全的,但使用多个操作可能不是。你的例子很好。说你有
// say it start at 1
Thread1: if(book.getAmountInInventory > 0)
Thread2: if(book.getAmountInInventory > 0)
Thread1: book.amountInInventory--
Thread2: book.amountInInventory--
金额现在是-1。
如果你使用synchronized
,那么在整个操作中持有锁会简单得多
synchronized (book) {
if(book.getAmountInInventory > 0) // no chance for a race condition here.
{
book.amountInInventory--
}
这里 AtomicInteger
是不够的。虽然它允许您以原子方式减少库存中的副本数量,但这还不够——您不需要仅以原子方式减少它,您还需要添加一些自定义逻辑。
我会使用普通的旧 int
,并使用显式 synchronized
块或方法保护其修改:
public class BookInventoryInfo {
private String bookTitle;
private int amountInInventory;
private int price;
public synchronized void checkOut() {
if (amountInInventory <= 0) {
throw new BookCheckoutException("No book in inventory");
}
amountInInventory--;
}
// All the other methods...
}
作为同步的替代方法,您还可以使用 compareAndSet
:
int a = book.amountInventory.get();
if (a > 0) {
boolean updated = book.amountInInventory.compareAndSet(a, a - 1);
}
这将只减少amountInInventory
的值,如果它的值仍然是a
,当你来更新它时。 compareAndSet
的 return 值表示该值是否已更改。
您可以将其包装在一个循环中,例如:
while (true) {
int a = book.amountInventory.get();
if (a == 0) {
return false; // To mean "no book in inventory";
}
if (book.amountInInventory.compareAndSet(a, a - 1)) {
return true; // To mean "there was a book in inventory, and it was removed".
}
}