Как заблокировать доступ на запись в массив из Thread при чтении

1

У меня два потока, работающих параллельно, и для получения информации о их внутренних результатах я создал массив int длиной 8. Что касается их id, они могут обновлять относительную область в массиве statu. Им не разрешают писать другие области. Более того, чтобы правильно получить и отобразить statu-массив, я пытаюсь написать метод getStatu. Получая результат, я хочу заблокировать других для записи в массив statu; к сожалению, я не знаю, как заблокировать других, чтобы написать массив statu, пока я получаю и показываю результат в методе getStatu. Как?

Примечание. Если есть какая-то часть, которую вы неправильно понимаете, скажите мне, мой друг, я исправлю

class A{
    Semaphore semaphore;
    int [] statu;  // statu is of length 8

    void update(int idOfThread, int []statu_){
        try {
            semaphore.acquire();
            int idx = idOfThread * 4;

            statu[idx] = statu_[0];
            statu[idx+1] = statu_[1];
            statu[idx+2] = statu_[2];
            statu[idx+3] = statu_[3];
        } catch (...) {

        } finally {
            semaphore.release();
        }
    }

    int[] getStatu(){
        // Block write access of threads
        //    display statu array
        //    return statu array as return value
        // release block, so threads can write to the array

    }
}
  • 0
    Вы можете выполнить эту работу с помощью java.util.concurrent.ConcurrentHashMap . Но, возможно, вы не должны. Этим вы привели бы к большому количеству споров и уменьшению параллелизма ваших потоков ... и да. Либо А есть singleton или statu и semaphore являются статическими. В противном случае ваши потоки не будут синхронизированы, поскольку они не будут использовать общую инфраструктуру.
  • 1
    Почему вы не используете ReentrantLock ?
Показать ещё 4 комментария
Теги:
multithreading
concurrency

5 ответов

0

Как сказал ac3, только вы знаете, что вы пытаетесь сделать.

Здесь решение, которое может быть полезно в случае, когда каждый поток, который вызывает update(), делает это часто, а вызовы getStatu() нечасты. Он сложный, но он позволяет большинству вызовов update() вообще не блокироваться.

static final int NUMBER_OF_WORKER_THREADS = ...;
final AtomicReference<CountDownLatch> pauseRequested = new AtomicReference<CountDownLatch>(null);
final Object lock = new Object();

int[] statu = ...

//called in "worker" thread.
void update() {
    if (pauseRequested.get() != null) {
        pause();
    }
    ... update my slots in statu[] array ...
}

private void pause() {
    notifyMasterThatIAmPaused();
    waitForMasterToLiftPauseRequest();
}

private void notifyMasterThatIAmPaused() {
    pauseRequested.get().countDown();
}

private void waitForMasterToLiftPauseRequest() {
    synchronized(lock) {
        while (pauseRequested.get() != null) {
            lock.wait();
        }
    }
}

//called in "master" thread

int[] getStatu( ) {
    int[] result;
    CountDownLatch cdl = requestWorkersToPause();
    waitForWorkersToPause(cdl);
    result = Arrays.copyOf(statu, statu.length);
    liftPauseRequest();
    return result;
}

private CountDownLatch requestWorkersToPause() {
    cdl = new CountDownLatch(NUMBER_OF_WORKER_THREADS);
    pauseRequested.set(cdl);
    return cdl;
}

private void waitForWorkersToPause(CountDownLatch cdl) {
    cdl.await();
}

private void liftPauseRequest() {
    synchronized(lock) {
        pauseRequested.set(null);
        lock.notifyAll();
    }
}
0
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
int[] statu;

void update() {
    lock.writeLock().lock();
    try {
        // update statu
    } finally {
        lock.writeLock().unlock();
    }
}

int[] getStatu() {
    lock.readLock().lock();
    try {
        // return statu
    } finally {
        lock.readLock().unlock();
    }
}
0

Попробуйте приведенный ниже код, он будет работать для вас. вызовите afterStatu().

class A {

    Semaphore semaphore;
    int[] statu; // statu is of length 8

    private boolean stuck;

    public A() {
    }

    void update(int idOfThread, int[] statu_) {

        // if true, control will not go further
        while (stuck);

        try {
            semaphore.acquire();
            int idx = idOfThread * 4;

            statu[idx] = statu_[0];
            statu[idx + 1] = statu_[1];
            statu[idx + 2] = statu_[2];
            statu[idx + 3] = statu_[3];
        } catch (Exception e) {

        } finally {
            semaphore.release();
        }
    }

    int[] getStatu() {
        // Block write access of threads
        stuck = true;
        // display statu array
        for (int eachStatu : statu) {
            System.out.println(eachStatu);
        }

        // return statu array as return value
        return statu;
    }

    public void afterStatu() {
        getStatu();
         // release block, so threads can write to the array
        stuck = false;
    }

}
0

Помимо использования другого механизма lock/snc, чем Семафор, просто предложение немного улучшить это.

Включение обоих массивов статуса [4] в один массив [8] не является лучшим решением. Рассмотрим задачу A, пишущую свою четверку: она должна блокировать задачу B, читающую то же самое, но нет смысла блокировать задачу B, записывая B quadruplet, и наоборот.

Вообще говоря, зернистость того, что блокируется, является одним из важных факторов: блокирование всей базы данных - это вздор (за исключением общей обработки, такой как резервное копирование), однако блокирование отдельных полей записи приведет к чрезмерным накладным расходам.

0

Есть, возможно, лучшие способы добраться туда, где вы хотите, но только вы знаете, что вы пытаетесь сделать. Идя по собственной схеме, есть вещи, которые вы делаете неправильно. Во-первых, в настоящее время вы не достигаете гранулированной блокировки, которую вы планируете. Для этого у вас должен быть массив семафоров. Таким образом, приобретение будет выглядеть примерно так:

semaphore[idOfThread].acquire();

Во-вторых, одна вещь, которую вы не поняли, заключается в том, что контролируемый доступ к данным между потоками является совместным действием. Вы не можете блокировать один поток и не заботиться о блокировке на другом и каким-то образом навязывать контроль доступа.

Поэтому, если вызывающий объект getStatu() не будет использовать тот же набор семафоров при проверке массива, лучше всего использовать getStatu(), чтобы создать новый массив int [], скопировав сегменты каждого потока после блокировки с соответствующим семафором. Таким образом, массив, возвращаемый getStatu(), будет моментальным снимком в точке вызова.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню