Возьмите вас, чтобы увидеть взрыв метода в JAVA!

Spring Boot Java Spring

Оригинал: Miss Sister Taste (идентификатор публичной учетной записи WeChat: xjjdog), добро пожаловать, пожалуйста, сохраните источник для перепечатки.

Чтобы понять, насколько извращен API Java, мы должны упомянуть队列Этот интерфейс многих людей, проработавших много лет, до сих пор очень сбивает с толку. Хотя очередь является фундаментальной структурой компьютерных алгоритмов, она не простоaddСюда.

После прочтения этой статьи, если вы увидите добавить, предложить и снова поставить, не расстраивайтесь!

1. Небольшой кусок кода

Угадайте, что выведет следующий код?

void run(Callable<Object> c){
    try{
        System.out.println(c.call());
    }catch (Exception ex){
        System.out.println(ex);
    }
}
void testSynchronousQueue(){
    Queue<Integer> q1 = new SynchronousQueue();
    run(()-> q1.add(1));

    Queue<Integer> q2 = new SynchronousQueue();
    run(()-> q1.offer(1));
}

Очень разочаровывает, обе казни провалились.

java.lang.IllegalStateException: Queue full
false

В первый раз используйтеaddметод, программа выдает исключение, указывающее, что очередь заполнена; во второй раз программа возвращаетfalse, что доказывает, что добавление не удалось. Поскольку нет возможности добавлять элементы в очередь, то и указать размер очереди негде. Так что толку от этой очереди!

2. Метод очереди

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

  • add(E e)Вставляет элемент в конец очереди. Выдает исключение, если его нельзя вставить
  • offer(E e)Вставка элемента в очередь
  • E remove()Удалить элемент из головы очереди, выдать исключение, если очередь пуста
  • E poll()Удаляет элемент из головы очереди или null, если очередь пуста
  • E element()Посмотрите на элемент head и сгенерируйте исключение, если очередь пуста.
  • E peek()Посмотрите на элемент head и верните null, если очередь пуста.

Видно, что в очереди есть только три основные операции: вставка новых элементов, просмотр заголовка очереди и сопоставление заголовка очереди. В зависимости от того, генерируется ли исключение, оно делится на две категории. 3x2=6, всего 6 методов.

Для студентов, которые любят писать вопросы, обычно используются такие вопросы, как предложение, опрос и просмотр, которые могут избежать раздражающей обработки исключений. Для обычного кодирования также рекомендуется использовать обычные API, но почему Java предоставляет нам два набора методов?

Причина в том, что интерфейс Queue наследует интерфейс Collection, а такие методы, как добавление и удаление, принадлежат интерфейсу Collection, а Queue должен реализовать набор. На самом деле метод add напрямую вызывает метод offer, зачем такой лишний набор API, вообще загадка.

public boolean add(E e) {
if (offer(e))
   return true;
else
   throw new IllegalStateException("Queue full");
}

Если исключение не выбрасывается, его легко забыть и обработать, что на самом деле является довольно надуманной причиной. Исходя из этого, могут ли люди создать так много методов с разными именами в такой важной базовой библиотеке классов?

3. Положи и возьми

По сравнению с приведенными выше запутанными add и offer, методы put и take действительно полезны. Но put и take не относятся к интерфейсу Queue, его атрибуцияBlockingQueue. Извините, я случайно перешел к параллельному пакету.

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

void testBlockingSynchronousQueue() throws InterruptedException {
    BlockingQueue<Integer> q1 = new SynchronousQueue();
    new Thread(()-> {
        try {
            q1.put(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
    new Thread(()-> {
        try {
            System.out.println(q1.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

Итак, давайте посмотрим на эти пары.

  • put(E e)Вставьте элемент, если очередь заполнена, он будет продолжать блокироваться в ожидании
  • E take()Получить головной элемент очереди, если очередь пуста, продолжайте ждать

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

Но это еще не конец. Заблокированные методы take и put можно только прервать Как заблокировать программу на время, а затем возобновить ее работу? Затем просто добавьте метод блокировки с отметкой времени.

BlockingQueueЯ выбрал методы предложения и опроса вместо метода «бери и ставь», и я не знаю, почему.

  • E poll(long timeout, TimeUnit unit)
  • логическое предложение (E e, долгое время ожидания, единица измерения TimeUnit) по-прежнему имеет возвращаемое значение

4. Как вы думаете, это конец?

Как вы думаете, это конец? нисколько. Нам нужно обратить внимание наLinkedList, легендарный класс, который реализует кеш LRU с помощью нескольких строк кода.

ArrayListЭто относительно чистый список, который реализует только интерфейс списка, ноLinkedListПросто немного больше аппетита. Поскольку разработчики API изо всех сил старались сделать этот связанный список более мощным, он наследует интерфейс Deque. Поскольку Deque наследует Queue, этот связанный список является не только очередью, но и двусторонней очередью.

Поэтому у них есть куча API для описания того, выполняется ли операция в начале очереди или в конце очереди.

  • addFirst управляет головой очереди, добавляя элементы
  • addLast управляет хвостом очереди, добавляя элементы
  • offerFirst управляет головой очереди, добавляя элементы
  • offerLast управляет хвостом очереди, добавляя элементы
  • removeFirst управляет головой очереди и удаляет элемент
  • removeLast работает в конце очереди и удаляет элементы
  • pollFirst управляет головой очереди и удаляет элемент
  • pollLast работает в конце очереди и удаляет элементы
  • getFirst Получает элемент head, похожий на element. TMD, почему бы не использовать элемент здесь?
  • getLast получает последний элемент очереди
  • peekFirst получает главный элемент очереди
  • peekLast получает последний элемент очереди

Конечно, есть еще pop и push, pop=removeFirst, push=addFirst. //Рекомендуется не использовать, слишком сложно запомнить.

приятно приятно, из-за концепции головы и хвоста размер API становится3x2x2=12индивидуальный! Добавление исходных 6, в общей сложности18(Игнорируйте поп и нажмите напрямую).

Вы должны сказать, почему нет метода блокировки, такого как «бери и клади». Причина в том, что LinkedList не является параллельной коллекцией, функция, которую вы ищете, находится вLinkedBlockingDequeСреди них обязательно будут takeFirst, takeLast, putLast, putFirst и т.д.

5. Размер очереди

Оглядываясь назад на SynchronousQueue, которую мы только что запустили, почему она возвращает ошибку при добавлении к ней элементов или извлечении элементов? Какова его емкость?

Это очень странный класс, его внутренняя емкость равна 0! Это жестко зашито в коде.

public int size() {
   return 0;
}

Он только устанавливает канал.Как только есть производство, потребители могут сразу его получить, и сам он не хранит никаких данных.Executors.newCachedThreadPool()Просто используйте SynchronousQueue.

Обычно используемые LinkedBlockingQueue и ArrayBlockingQueue ограничены.

Но тут странная штука это класс, плюс еще идиConcurrentLinkedQueue, как видно из названия, это не блокирующий параллельный класс, поэтому в нем нет методов типа take и put. Кроме того, он не ограничен, поэтому будьте осторожны при его использовании. Вы могли бы сказать, что каждый раз, когда я сужу,size()Метод, чтобы увидеть, находится ли он за пределами или нет.

public int size() {
    int count = 0;
    for (Node<E> p = first(); p != null; p = succ(p))
        if (p.item != null)
           // Collection.size() spec says to max out
           if (++count == Integer.MAX_VALUE)
                break;
    return count;
}

Как показано в приведенном выше коде, именно здесь находятся ямы.Метод размера не является временным уровнем O(1). xjjdog сильно над ним помучился, и в конце концов не осмелился использовать его без разбора.

End

Это видно из приведенного выше описания. Для очереди существует три набора интерфейсов: вставка, извлечение и обнаружение; в зависимости от того, было ли выдано исключение, оно делится на два набора, один из которых выдает исключение, а другой возвращает значение напрямую. При добавлении двусторонней очереди необходимо различать начало и конец очереди, если это блокирующая очередь, необходимо добавить еще одно измерение.

Итак, для блокирующей двусторонней очереди основными методами ее работы являются:(3[基本]x2[异常与返回值]+4[阻塞加超时])x3[队头队尾]=5x2x3=30В одну сторону, это корольLinkedBlockingDeque.

Об авторе: Miss Sister Taste (xjjdog), общедоступный аккаунт, который не позволяет программистам идти в обход. Сосредоточьтесь на инфраструктуре и Linux. Десять лет архитектуры, десятки миллиардов ежедневного трафика, обсуждение с вами мира высокой параллелизма, дающие вам другой вкус. Мой личный WeChat xjjdog0, добро пожаловать в друзья для дальнейшего общения.