В просторечии класс инструментов параллелизма Java — Semaphore, Exchanger

Java задняя часть база данных
В просторечии класс инструментов параллелизма Java — Semaphore, Exchanger

Оригинальная статья, краткое изложение опыта и жизненные перипетии на всем пути от набора в школу до фабрики.

Нажмите, чтобы узнать подробностиwww.codercc.com

1. Контролируйте одновременный доступ к ресурсам — семафор

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

Семафор можно использовать для управления потоком, особенно в приложениях с ограниченными общедоступными ресурсами, такими как соединения с базой данных. Если есть несколько потоков, читающих данные, данные должны быть сохранены в базе данных, а максимально доступное подключение к базе данных составляет всего 10. В настоящее время вам необходимо использовать семафор для управления количеством потоков, которые могут одновременно получать доступ к подключению к базе данных. ресурсы.Максимальное количество всего 10 штук. Семафор особенно удобен в сценариях приложений, где использование ресурсов ограничено.

Давайте рассмотрим основные методы Semaphore:

//获取许可,如果无法获取到,则阻塞等待直至能够获取为止
void acquire() throws InterruptedException
//同acquire方法功能基本一样,只不过该方法可以一次获取多个许可
void acquire(int permits) throws InterruptedException
//释放许可
void release()
//释放指定个数的许可
void release(int permits)
//尝试获取许可,如果能够获取成功则立即返回true,否则,则返回false
boolean tryAcquire()
//与tryAcquire方法一致,只不过这里可以指定获取多个许可
boolean tryAcquire(int permits)
//尝试获取许可,如果能够立即获取到或者在指定时间内能够获取到,则返回true,否则返回false
boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
//与上一个方法一致,只不过这里能够获取多个许可

boolean tryAcquire(int permits, long timeout, TimeUnit unit)

//返回当前可用的许可证个数
int availablePermits()
//返回正在等待获取许可证的线程数
int getQueueLength()
//是否有线程正在等待获取许可证
boolean hasQueuedThreads()
//获取所有正在等待许可的线程集合
Collection<Thread> getQueuedThreads()

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

один пример

Ниже приведен простой пример, иллюстрирующий конкретное использование семафора. Смоделируем такой сценарий. Однажды завучу нужно было, чтобы 10 учеников в классе вышли на подиум, чтобы заполнить форму, но учитель приготовил только ручки 5. Таким образом, можно гарантировать, что только 5 учеников могут получить ручки и заполнить форму. Форма в то же время, и ни один из учеников не получил ручки.Вы можете получить ручку, чтобы заполнить форму только после того, как предыдущие одноклассники использовали ее. Пример кода выглядит следующим образом:

public class SemaphoreDemo {
//表示老师只有10支笔
private static Semaphore semaphore = new Semaphore(5);

public static void main(String[] args) {

    //表示50个学生
    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i &lt; 10; i++) {
        service.execute(() -&gt; {
            try {
                System.out.println(Thread.currentThread().getName() + "  同学准备获取笔......");
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + "  同学获取到笔");
                System.out.println(Thread.currentThread().getName() + "  填写表格ing.....");
                TimeUnit.SECONDS.sleep(3);
                semaphore.release();
                System.out.println(Thread.currentThread().getName() + "  填写完表格,归还了笔!!!!!!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
    service.shutdown();
}

} Выходной результат:

одноклассники pool-1-thread-1 готовы получить ручку... Одноклассники pool-1-thread-1 получают ручку pool-1-thread-1 заполнить форму ..... Одноклассники pool-1-thread-2 готовы получить ручку... Одноклассники pool-1-thread-2 получают ручку pool-1-thread-2 Заполните форму ..... Одноклассники pool-1-thread-3 готовы получить ручку... одноклассники pool-1-thread-4 готовы получить ручку... Одноклассники pool-1-thread-3 получают ручку одноклассники pool-1-thread-4 получают ручку pool-1-thread-4 Заполните форму ..... pool-1-thread-3 Заполните форму ..... одноклассники pool-1-thread-5 готовы получить ручку... Одноклассники pool-1-thread-5 получают ручку pool-1-thread-5 Заполните форму .....

pool-1-thread-6 одноклассники готовы получить ручку... pool-1-thread-7 одноклассники готовы получить ручку... одноклассники pool-1-thread-8 готовы получить ручки...   одноклассники pool-1-thread-9 готовы получить ручки...   одноклассники pool-1-thread-10 готовы получить ручки...  

скопировать код

pool-1-thread-4 填写完表格,归还了笔!!!!!! pool-1-thread-9 同学获取到笔 pool-1-thread-9 填写表格ing..... pool-1-thread-5 填写完表格,归还了笔!!!!!! pool-1-thread-7 同学获取到笔 pool-1-thread-7 填写表格ing..... pool-1-thread-8 同学获取到笔 pool-1-thread-8 填写表格ing..... pool-1-thread-1 填写完表格,归还了笔!!!!!! pool-1-thread-6 同学获取到笔 pool-1-thread-6 填写表格ing..... pool-1-thread-3 填写完表格,归还了笔!!!!!! pool-1-thread-2 填写完表格,归还了笔!!!!!! pool-1-thread-10 同学获取到笔 pool-1-thread-10 填写表格ing..... pool-1-thread-7 填写完表格,归还了笔!!!!!! pool-1-thread-9 填写完表格,归还了笔!!!!!! pool-1-thread-8 填写完表格,归还了笔!!!!!! pool-1-thread-6 填写完表格,归还了笔!!!!!! pool-1-thread-10 填写完表格,归还了笔!!!!!!

Согласно анализу выходных результатов, максимальное количество лицензий, разрешенных Semaphore, равно 5, то есть максимальное количество одновременно выполняемых потоков равно 5. Видно, что первые 5 потоков (первые 5 студентов) получают сначала перо, а затем заполнение таблицы, а 5 потоков 6-10 могут только блокировать и ждать, потому что они не могут получить разрешение. когда нитьpool-1-thread-4После выпуска лицензииpool-1-thread-9Вы можете получить разрешение и продолжить выполнение. То же самое справедливо и для выполнения других потоков. Как видно из этого примера,Семафор вполне подходит для одновременного управления доступом к специальным ресурсам, если есть бизнес-сценарий, требующий управления трафиком, Семафору можно отдать приоритет.

2. Инструмент для обмена данными между потоками - Exchanger

Exchanger — это класс инструментов для взаимодействия между потоками, который используется для обмена данными между двумя потоками. Он обеспечивает точку синхронизации обмена, в которой два потока могут обмениваться данными. Конкретный обмен данными реализуется методом обмена.Если поток выполняет метод обмена первым, он будет ждать, пока другой поток выполнит метод обмена синхронно.В это время два потока достигли точки синхронизации, и два потока может обмениваться данными.

Помимо конструктора без параметров, основной метод Exchanger также очень прост:

//当一个线程执行该方法的时候,会等待另一个线程也执行该方法,因此两个线程就都达到了同步点
//将数据交换给另一个线程,同时返回获取的数据
V exchange(V x) throws InterruptedException
//同上一个方法功能基本一样,只不过这个方法同步等待的时候,增加了超时时间
V exchange(V x, long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException

один пример

Обменник прост для понимания, вот простой пример, чтобы увидеть его конкретное использование. Давайте смоделируем такую ​​ситуацию.В эпоху юношеской средней школы, во время внеклассного периода, мальчики часто посылали любовные письма понравившимся девочкам в коридоре.Я думаю, что все так делали :). Мальчик сначала подойдет к двери класса девочки, а потом дождется выхода девочки.Класс является точкой синхронизации, а затем обмениваться токенами друг с другом, то есть обмениваться данными друг с другом. Теперь давайте смоделируем этот сценарий.

public class ExchangerDemo {
    private static Exchanger<String> exchanger = new Exchanger();
public static void main(String[] args) {

    //代表男生和女生
    ExecutorService service = Executors.newFixedThreadPool(2);

    service.execute(() -&gt; {
        try {
            //男生对女生说的话
            String girl = exchanger.exchange("我其实暗恋你很久了......");
            System.out.println("女孩儿说:" + girl);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    service.execute(() -&gt; {
        try {
            System.out.println("女生慢慢的从教室你走出来......");
            TimeUnit.SECONDS.sleep(3);
            //男生对女生说的话
            String boy = exchanger.exchange("我也很喜欢你......");
            System.out.println("男孩儿说:" + boy);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });

}

}

Выходной результат:

скопировать код

女生慢慢的从教室你走出来...... 男孩儿说:我其实暗恋你很久了...... 女孩儿说:我也很喜欢你......

Этот пример очень прост, и он очень хорошо иллюстрирует основное использование Exchanger. Когда оба потока достигают точки синхронизации, где вызывается метод обмена, два потока могут обмениваться данными друг с другом.