Пожалуйста, указывайте адрес этой статьи при перепечатке:woo woo Краткое описание.com/fear/ отправить 00 ах ах 6 отправить 66…
Адрес источника:git ee.com/sunny more/ ах…
Санни сначала расскажет о понимании асинхронности и синхронности:
Синхронный вызов: вызывающий объект продолжает ожидать возвращаемого результата в процессе вызова. Асинхронный вызов: во время вызывающего процесса вызывающий объект не ожидает непосредственно возвращаемого результата, а выполняет другие задачи, а возвращаемый результат обычно имеет форму функции обратного вызова.
На самом деле, разница между ними все еще очень очевидна, и я не буду здесь вдаваться в подробности, а поговорим в основном о том, как Java преобразует асинхронные вызовы в синхронизацию. Другими словами, необходимо непрерывно блокировать до тех пор, пока результат вызова не будет получен в процессе асинхронного вызова. Чтобы не продаваться, сначала перечислите пять методов, а потом по порядку приведите примеры:
- Использование методов ожидания и уведомления
- Используйте условные блокировки
- Future
- Использование защелки обратного отсчета
- Использование циклического барьера
0. Создайте асинхронный вызов
Прежде всего, чтобы написать демонстрацию, вам нужно сначала написать инфраструктуру Здесь вам нужно построить модель асинхронного вызова. Класс асинхронного вызова:
public class AsyncCall {
private Random random = new Random(System.currentTimeMillis());
private ExecutorService tp = Executors.newSingleThreadExecutor();
//demo1,2,4,5调用方法
public void call(BaseDemo demo){
new Thread(()->{
long res = random.nextInt(10);
try {
Thread.sleep(res*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
demo.callback(res);
}).start();
}
//demo3调用方法
public Future<Long> futureCall(){
return tp.submit(()-> {
long res = random.nextInt(10);
try {
Thread.sleep(res*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return res;
});
}
public void shutdown(){
tp.shutdown();
}
}
В основном нас интересует метод call.Этот метод получает демонстрационный параметр, запускает поток, выполняет определенные задачи в потоке и использует метод обратного вызова демо для вызова функции обратного вызова. Вы заметили, что возвращаемый результат здесь представляет собой длинное целое число [0,10), а результат — несколько, пусть поток спит, как долго — это в основном для лучшего наблюдения за экспериментальными результатами и имитации времени обработки в процесс асинхронного вызова.
Что касается методов futureCall и shutdown, а также пула потоков tp, все они подготовлены для реализации в demo3 с использованием Future.
Базовый класс для демонстрации:
public abstract class BaseDemo {
protected AsyncCall asyncCall = new AsyncCall();
public abstract void callback(long response);
public void call(){
System.out.println("发起调用");
asyncCall.call(this);
System.out.println("调用返回");
}
}
BaseDemo очень простой.Он содержит экземпляр класса асинхронного вызова, и есть метод call для инициирования асинхронных вызовов.Конечно, есть еще абстрактный метод callback, который должен быть реализован каждым демо-в основном в обратном вызове для выполнения соответствующей обработки для достижения асинхронного вызова синхронной цели.
1. Используйте методы ожидания и уведомления
Этот метод фактически использует механизм блокировки и напрямую вставляет код:
public class Demo1 extends BaseDemo{
private final Object lock = new Object();
@Override
public void callback(long response) {
System.out.println("得到结果");
System.out.println(response);
System.out.println("调用结束");
synchronized (lock) {
lock.notifyAll();
}
}
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
demo1.call();
synchronized (demo1.lock){
try {
demo1.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程内容");
}
}
Видно, что после того, как вызов инициирован, основной поток использует ожидание для блокировки, ожидая вызова метода notify или notifyAll в обратном вызове для пробуждения. Обратите внимание, что, как всем известно, и ждать, и уведомлять здесь нужно сначала получить блокировку объекта. В основном потоке мы наконец печатаем контент, который также используется для проверки результатов эксперимента.Если нет ожидания и уведомления, содержимое основного потока будет напечатано сразу после содержимого вызова, и как наш код выше, содержимое основного потока всегда будет ждать. Оно не будет печататься до тех пор, пока не завершится вызов функции обратного вызова. Без использования синхронной операции выведите результат:
发起调用
调用返回
主线程内容
得到结果
1
调用结束
И после использования синхронной операции:
发起调用
调用返回
得到结果
9
调用结束
主线程内容
2. Используйте условные блокировки
Аналогично принципу метода 1:
public class Demo2 extends BaseDemo {
private final Lock lock = new ReentrantLock();
private final Condition con = lock.newCondition();
@Override
public void callback(long response) {
System.out.println("得到结果");
System.out.println(response);
System.out.println("调用结束");
lock.lock();
try {
con.signal();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
Demo2 demo2 = new Demo2();
demo2.call();
demo2.lock.lock();
try {
demo2.con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
demo2.lock.unlock();
}
System.out.println("主线程内容");
}
}
По сути, он ничем не отличается от метода 1, за исключением того, что здесь используется условная блокировка, а механизм блокировки у них разный.
3. Future
Метод использования Future не такой, как раньше, и асинхронный метод, который мы вызываем, тоже другой.
public class Demo3{
private AsyncCall asyncCall = new AsyncCall();
public Future<Long> call(){
Future<Long> future = asyncCall.futureCall();
asyncCall.shutdown();
return future;
}
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
System.out.println("发起调用");
Future<Long> future = demo3.call();
System.out.println("返回结果");
while (!future.isDone() && !future.isCancelled());
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("主线程内容");
}
}
Мы вызываем метод futureCall. Метод отправит Callable в пул потоков tp, а затем вернет Future. Это Future получено из вызова в нашей демонстрации 3. После получения объекта future мы можем закрыть пул потоков и вызвать метод отключения asyncCall. Есть одно замечание по поводу закрытия пула потоков, давайте вернемся и посмотрим на метод выключения asyncCall:
public void shutdown(){
tp.shutdown();
}
Обнаружено, что просто вызывается метод отключения пула потоков, и тогда мы говорим, внимание Лучше всего не использовать здесь метод tp shutdownNow, который попытается прервать выполнение задачи в потоке; то есть, если вы используете этот метод, возможно, что задача, соответствующая нашему будущему, будет прервана, и результат выполнения не может быть получен. Затем мы обращаем внимание на содержимое в основном потоке, блокировка основного потока реализуется нами, а состояние выполнения оценивается по isDone и isCancelled будущего, пока выполнение не будет завершено или отменено. Затем мы печатаем результат get.
4. Использование CountDownLatch
Использование CountDownLatch, вероятно, является наиболее распространенным в повседневном программировании, и оно также выглядит относительно элегантно:
public class Demo4 extends BaseDemo{
private final CountDownLatch countDownLatch = new CountDownLatch(1);
@Override
public void callback(long response) {
System.out.println("得到结果");
System.out.println(response);
System.out.println("调用结束");
countDownLatch.countDown();
}
public static void main(String[] args) {
Demo4 demo4 = new Demo4();
demo4.call();
try {
demo4.countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程内容");
}
}
Как вы обычно используете, здесь метод await CountDownLatch используется для блокировки в основном потоке, а метод countDown используется в обратном вызове, чтобы заставить ожидающую часть других потоков продолжать работать. Конечно, это то же самое, что и в demo1 и demo2.Для заблокированной части основного потока можно установить таймаут, и блок уже не может быть заблокирован по истечении таймаута.
5. Использование циклического барьера
Ситуация CyclicBarrier чем-то похожа на CountDownLatch:
public class Demo5 extends BaseDemo{
private CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
@Override
public void callback(long response) {
System.out.println("得到结果");
System.out.println(response);
System.out.println("调用结束");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Demo5 demo5 = new Demo5();
demo5.call();
try {
demo5.cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("主线程内容");
}
}
Обратите внимание, что CyclicBarrier и CountDownLatch только похожи, и между ними есть определенные различия. Например, одно можно понимать как сложение, и оно будет выполняться вместе после прибавления к этому числу; другое — это вычитание, и оно будет продолжать выполняться при уменьшении до 0. Один повторяемый, другой не бла-бла-бла. Кроме того, при использовании CyclicBarrier следует обратить внимание на два момента. Во-первых, при инициализации номер параметра должен быть установлен в 2, потому что асинхронный вызов здесь является потоком, а основной поток — потоком, и выполнение может продолжаться, когда оба потока ждут, что также является частью, которая отличается от CountDownLatch. Второй момент так же касается значения параметра инициализации, который здесь к демо отношения не имеет.При программировании нужно быть более внимательным.Если это значение задано слишком большим, то оно больше, чем количество потоков в пул потоков, то это очень легко вызвало тупик.
Суммировать
Подводя итог, на этот раз необходимо сказать о нескольких методах. По сути все методы основаны на одном принципе, то есть блокировка и ожидание результата в вызывающем потоке, и разблокировка состояния блокировки в callback-функции. Если у вас есть другие методы, добро пожаловать на обсуждение со мной~
Почта:zsunny@yeah.net
Эта статья приветствуется для перепечатки, пожалуйста, укажите адрес этой статьи:woo woo Краткое описание.com/fear/ отправить 00 ах ах 6 отправить 66…