Вероятно, наиболее интересным с точки зрения синхронизации является класс Exchanger, предназначенный для упрощения процесса обмена данными между двумя потоками исполнения.
Принцип действия класса Exchanger очень прост: он ожидает до тех пор, пока два отдельных потока исполнения не вызовут его метод exchange(). Как только это произойдет, он произведет обмен данными, предоставляемыми обоими потоками. Такой механизм обмена данными не только изящен, но и прост в применении.
Нетрудно представить, как воспользоваться классом Exchanger. Например, один поток исполнения подготавливает буфер для приема данных через сетевое соединение, а другой — заполняет этот буфер данными, поступающими через сетевое соединение. Оба потока исполнения действуют совместно, поэтому всякий раз, когда требуется новая буферизация, осуществляется обмен данными.
Класс Exchanger является обобщенным и объявляется приведенным ниже образом, где параметр V определяет тип обмениваемых данных.
1 |
Exchanger<V> |
В классе Exchanger определяется единственный метод exchange(), имеющий следующие общие формы:
1 2 3 |
V exchange(V буфер) throws InterruptedException V exchange(V буфер, long ожидание, TimeUnit единица_времени) throws InterruptedException, TimeoutException |
где параметр буфер обозначает ссылку на обмениваемые данные. Возвращаются данные, полученные из другого потока исполнения.
Вторая форма метода exchange() позволяет определить время ожидания. Главная особенность метода exchange() состоит в том, что он не завершится успешно до тех пор, пока не будет вызван для одного и того же объекта типа Exchanger из двух отдельных потоков исполнения. Подобным образом метод exchange() синхронизирует обмен данными.
Дорогие читатели, в планах менять дизайн блога. Думаю натянуть HTML шаблон ThemeForest Findeo на WordPress, или найти подобный. Если есть какие-нибудь идеи обязательно оставьте их в комментарии.
В приведенном ниже примере программы демонстрируется применения класса Exchanger. В этой программе создаются два потока исполнения.
В одном потоке исполнения создается пустой буфер, принимающий данные из другого потока исполнения. Таким образом, первый поток исполнения обменивает пустую символьную строку на полную.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
// Пример применения класса Exchanger import java.util.concurrent.Exchanger; class ExgrDemo { public static void main(String args[]) { Exchanger<String> exgr = new Exchanger<String>(); new UseString(exgr); new MakeString(exgr); } } // Поток типа Thread, формирующий символьную строку class MakeString implements Runnable { Exchanger<String> ex; String str; MakeString(Exchanger<String> c) { ex = c; str = new String(); new Thread(this).start(); } public void run() { char ch = 'A'; for(int i = 0; i < 3; i++) { // заполнить буфер for(int j = 0; j < 5; j++) { str += (char) ch++; } try { // обменять заполненный буфер на пустой str = ex.exchange(str); } catch(InterruptedException exc) { System.out.println(exc); } } } } // Поток типа Thread, использующий символьную строку class UseString implements Runnable { Exchanger<String> ex; String str; UseString(Exchanger<String> c) { ex = c; new Thread(this).start(); } public void run() { for(int i = 0; i < 3; i++) { try { // обменять пустой буфер на заполненный str = ex.exchange(new String()); System.out.println("Получено: " + str); } catch(InterruptedException exc) { System.out.println(exc); } } } } |
Ниже показаны результаты выполнения данной программы.
1 2 3 |
Получено: ABCDE Получено: FGHIJ Получено: KLMNO |
В методе main() данной программы сначала создается объект класса Exchanger. Этот объект служит для синхронизации обмена символьными строками между классами MakeString и UseString. Класс MakeString заполняет символьную строку данными, а класс UseString обменивает пустую символьную строку на полную, отображая затем ее содержимое.
Обмен пустой символьной строки на полную в буфере синхронизируется методом exchange(), который вызывается из метода run() в классах MakeString и UseString.