Использование многопоточного кода и условных переменных - PullRequest
1 голос
/ 17 ноября 2010

Многопоточный фрагмент кода обращается к ресурсу (например, к файловой системе) асинхронно.

Для достижения этого я буду использовать условные переменные.Предположим, что FileSystem является интерфейсом, подобным:

class FileSystem {
    // sends a read request to the fileSystem
    read(String fileName) {
        // ...
        // upon completion, execute a callback
        callback(returnCode, buffer);
    }
}

У меня есть приложение, которое обращается к FileSystem.Предположим, я могу выполнить несколько чтений с помощью метода readFile().Операция должна записать данные в переданный ей байтовый буфер.

// constructor
public Test() {
    FileSystem disk = ...
    boolean readReady = ...
    Lock lock = ...

    Condition responseReady = lock.newCondition();
}

// the read file method in quesiton
public void readFile(String file) {
    try {
        lock.lock(); // lets imagine this operation needs a lock

        // this operation may take a while to complete; 
        // but the method should return immediately
        disk.read(file); 

        while (!readReady) { // <<< THIS
            responseReady.awaitUninterruptibly();
        }
    } 
    finally {
        lock.unlock();
    }
}

public void callback(int returnCode, byte[] buffer) {
    // other code snipped...

    readReady = true;  // <<< AND THIS
    responseReady.signal();
}

Это правильный способ использования условных переменных?readFile() немедленно вернется?

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

1 Ответ

1 голос
/ 17 ноября 2010

В вашем вопросе многое отсутствует (т. Е. Нет конкретного упоминания тем), но я все равно постараюсь ответить.

Ни блокировка, ни условные переменные не дают фоновых возможностей - они просто используются для потока, ожидающего сигналов от других потоков. Хотя вы не упоминаете об этом, метод disk.read(file) может порождать поток для выполнения ввода-вывода, а затем немедленно возвращаться, но вызывающая сторона все равно будет сидеть в цикле readReady, что кажется бессмысленным. Если вызывающий должен ждать, он может сам выполнить IO.

Лучшим примером может быть использование чего-то вроде сервиса Java 5 Executors:

 ExecutorService pool = Executors.newFixedThreadPool(int numThreads);

Затем вы можете позвонить pool.submit(Callable), чтобы передать задание, которое будет выполнено в фоновом режиме, в другом потоке (когда у пула будет следующий доступный). Submit возвращает Future, который вызывающий может использовать, чтобы выяснить, завершена ли фоновая задача. Он также может возвращать объект результата. Одновременные классы позаботятся о логике блокировки и условного сигнала / ожидания для вас.

Надеюсь, это поможет.

p.s. Кроме того, вы должны сделать readReady энергозависимым, поскольку он не синхронизирован.

...