Помимо общей синхронизации, которая основана на бите блокировки, который есть у каждого объекта Java, у вас есть более сложные синхронизаторы в Java, такие как:
- Семафор — используйте концепцию разрешения, чтобы указать максимальное количество разрешенных потоков в одном месте. Когда вы используете значение 1, поведение аналогично синхронизации, также называется двоичным семафором. Однако здесь есть большая разница: вы получаете разрешение на семафор, а не блокирующий объект, это просто переменная для подсчета, когда поток получает разрешение и когда поток выпускает разрешение, своего рода счетчик. Единственное, что у вас есть — блокировка потоков, пока не будет доступно разрешение. В приведенном ниже примере мы определяем 3 как количество разрешений, поэтому после получения 3 поток 4 будет ожидать освобождения, прежде чем продолжить его выполнение.
01
02
03
04
05
06
07
08
09
10
|
// Define the semaphore to control 3 permits. // 3 Threads can acquire the mySemaphore Semaphore mySemaphore = new Semaphore( 3 , true ); // 3 threads can execute this line of code. The 4 thread must wait for a release mySemaphore.acquire(); // .. somewhere in the code a thread releases the mySemaphore, // and now the next waiting thread can acquire mySemaphore.release(); |
- CountDownLatch — Инициализируйте этот класс числом (для обратного отсчета), и когда он достигнет 0, ожидающий поток разблокируется и продолжит свой путь. (После ожидания защелка не может быть использована повторно)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
// Initializes a countdown starting from 3 CountDownLatch latch = new CountDownLatch( 3 ); // ... other threads are running... // Some thread blocks and waits for the latch countdown // to reach "0" latch.await(); // ... code, methods, other objects... etc... // ... at some place the OTHER threads do the countdown, // decrementing the latch.. when it reachs 0 // the blocked thread with the "await()" follows its way latch.countDown(); |
- CyclicBarrier — этот класс ведет себя как обратный к CountDownLatch. После N await () заблокированные потоки могут следовать своим путем. (CyclicBarrier можно использовать повторно)
1
2
3
4
5
6
7
8
|
// 3 threads must await before can unblock CyclicBarrier barrier = new CyclicBarrier( 3 ); // threads they block here until the 3 is reached barrier.await(); // after 3 threads in await this code will run! System.out.println("Thank you to the 3 friends who awaited for me!”); |
- Phaser — очень сложный синхронизатор, сочетание CountDownLatch и CyclicBarrier, с множеством настраиваемых параметров. Если вам нужно поведение, подобное двум предыдущим синхронизаторам, но их было недостаточно, вам нужно углубиться в этот. Он ведет себя как CyclicBarrier, но вы можете зарегистрировать набор потоков и в любое время отменить регистрацию, достигнув уровня настройки, невозможного с другими синхронизаторами. Подумайте о необходимости ожидания потоков, прежде чем вы сможете продолжить или запустить другой набор задач. Больше информации об этом на сайте Oracle:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Phaser.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
void runTasks(List<Runnable> tasks) { // Initialize the phaser, "1" to register self final Phaser phaser = new Phaser( 1 ); // create and start threads for ( final Runnable task : tasks) { // register here phaser.register(); new Thread() { public void run() { // await all creation phaser.arriveAndAwaitAdvance(); task.run(); } }.start(); } // allow threads to start and deregister self phaser.arriveAndDeregister(); } |
- Обменник . Лучшее объяснение дает сам документ Oracle: «Точка синхронизации, в которой потоки могут связывать и менять элементы в парах ». Один поток хочет отправить информацию другому потоку и блокирует ожидание отправки данных, и в EXCHANGE получает то, что другой поток тоже хочет отправить! Такое поведение происходит с обеих сторон!
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
// Create the exchanger. // We choose String as the data datatype Exchanger<String> ex = new Exchanger<String>(); // // .... Somewhere at Thread 1, // // I will block until I can send str1 to Thread 2, and receive a value too! String str1 = "value to send from Thread 1 to Thread 2" ; String valueReturnedFromThread2 = ex.exchange(str1); // // ... Somewhere at Thread 2, // // I will block until I can send str2 to Thread 1 // I will receive a value from Thread 1 too! String str2 = "value to send to Thread 1 from Thread 2" ; String valueReturnedFromThread1 = ex.exchange(str2); |
Ссылка: Пять продвинутых синхронизаторов Java, которые вы, вероятно, не знаете от нашего партнера JCG Богдана Бандривского в блоге Java User Group из Львова .