У меня два потока, работающих параллельно, и для получения информации о их внутренних результатах я создал массив 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
}
}
Как сказал 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();
}
}
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();
}
}
Попробуйте приведенный ниже код, он будет работать для вас. вызовите 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;
}
}
Помимо использования другого механизма lock/snc, чем Семафор, просто предложение немного улучшить это.
Включение обоих массивов статуса [4] в один массив [8] не является лучшим решением. Рассмотрим задачу A, пишущую свою четверку: она должна блокировать задачу B, читающую то же самое, но нет смысла блокировать задачу B, записывая B quadruplet, и наоборот.
Вообще говоря, зернистость того, что блокируется, является одним из важных факторов: блокирование всей базы данных - это вздор (за исключением общей обработки, такой как резервное копирование), однако блокирование отдельных полей записи приведет к чрезмерным накладным расходам.
Есть, возможно, лучшие способы добраться туда, где вы хотите, но только вы знаете, что вы пытаетесь сделать. Идя по собственной схеме, есть вещи, которые вы делаете неправильно. Во-первых, в настоящее время вы не достигаете гранулированной блокировки, которую вы планируете. Для этого у вас должен быть массив семафоров. Таким образом, приобретение будет выглядеть примерно так:
semaphore[idOfThread].acquire();
Во-вторых, одна вещь, которую вы не поняли, заключается в том, что контролируемый доступ к данным между потоками является совместным действием. Вы не можете блокировать один поток и не заботиться о блокировке на другом и каким-то образом навязывать контроль доступа.
Поэтому, если вызывающий объект getStatu() не будет использовать тот же набор семафоров при проверке массива, лучше всего использовать getStatu(), чтобы создать новый массив int [], скопировав сегменты каждого потока после блокировки с соответствующим семафором. Таким образом, массив, возвращаемый getStatu(), будет моментальным снимком в точке вызова.
java.util.concurrent.ConcurrentHashMap
. Но, возможно, вы не должны. Этим вы привели бы к большому количеству споров и уменьшению параллелизма ваших потоков ... и да. Либо А естьsingleton
илиstatu
иsemaphore
являются статическими. В противном случае ваши потоки не будут синхронизированы, поскольку они не будут использовать общую инфраструктуру.ReentrantLock
?