Должен ли я использовать атомное целое число или синхронизировать - PullRequest
0 голосов
/ 14 декабря 2018

Я немного запутался в использовании atomic / volatile / sync в моем коде.Допустим, у меня есть объект информации о книге в книжном магазине, и, например, может случиться так, что два потока захотят взять одну и ту же книгу, а сумма в инвентаре всего 1, как я могу обещать, что только один поток возьмет книгу?я должен использовать синхронизацию?BookInventoryInfo:

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--
}

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

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...
}
0 голосов
/ 14 декабря 2018

В качестве альтернативы синхронизации вы также можете использовать compareAndSet:

int a = book.amountInventory.get();
if (a > 0) {
  boolean updated = book.amountInInventory.compareAndSet(a, a - 1);
}

Это будет только уменьшать значение amountInInventory, еслиего значение все еще равно a, когда вы приходите обновить его.Возвращаемое значение compareAndSet указывает, было ли значение изменено или нет.

Вы можете заключить это в цикл, что-то вроде:

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".
  }
}
0 голосов
/ 14 декабря 2018

Вы должны использовать 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--
    }
...