Учебники

Java Concurrency — Краткое руководство

Java Concurrency — Обзор

Java — это многопоточный язык программирования, что означает, что мы можем разрабатывать многопоточные программы с использованием Java. Многопоточная программа содержит две или более частей, которые могут работать одновременно, и каждая из них может одновременно выполнять разные задачи, оптимально используя доступные ресурсы, особенно если на вашем компьютере установлено несколько процессоров.

По определению многозадачность — это когда несколько процессов совместно используют общие ресурсы обработки, такие как ЦП. Многопоточность расширяет идею многозадачности в приложениях, где вы можете разделить определенные операции в рамках одного приложения на отдельные потоки. Каждый из потоков может работать параллельно. ОС делит время обработки не только между различными приложениями, но и между каждым потоком в приложении.

Многопоточность позволяет вам писать так, чтобы несколько действий могли выполняться одновременно в одной и той же программе.

Жизненный цикл потока

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

Нить Java

Ниже приведены этапы жизненного цикла —

  • Новый — новый поток начинает свой жизненный цикл в новом состоянии. Он остается в этом состоянии, пока программа не запустит поток. Это также упоминается как прирожденная нить .

  • Runnable — после запуска только что созданного потока поток становится работоспособным. Поток в этом состоянии считается выполняющим свою задачу.

  • Ожидание — иногда поток переходит в состояние ожидания, пока поток ожидает, пока другой поток выполнит задачу. Поток возвращается в состояние выполнения только тогда, когда другой поток сигнализирует ожидающему потоку о продолжении выполнения.

  • Временное ожидание — работающий поток может войти в состояние ожидания по времени в течение определенного интервала времени. Поток в этом состоянии возвращается в работоспособное состояние, когда истекает этот временной интервал или когда происходит ожидаемое событие.

  • Завершено (Dead) — работающий поток входит в завершенное состояние, когда он завершает свою задачу или иным образом завершает свою работу.

Новый — новый поток начинает свой жизненный цикл в новом состоянии. Он остается в этом состоянии, пока программа не запустит поток. Это также упоминается как прирожденная нить .

Runnable — после запуска только что созданного потока поток становится работоспособным. Поток в этом состоянии считается выполняющим свою задачу.

Ожидание — иногда поток переходит в состояние ожидания, пока поток ожидает, пока другой поток выполнит задачу. Поток возвращается в состояние выполнения только тогда, когда другой поток сигнализирует ожидающему потоку о продолжении выполнения.

Временное ожидание — работающий поток может войти в состояние ожидания по времени в течение определенного интервала времени. Поток в этом состоянии возвращается в работоспособное состояние, когда истекает этот временной интервал или когда происходит ожидаемое событие.

Завершено (Dead) — работающий поток входит в завершенное состояние, когда он завершает свою задачу или иным образом завершает свою работу.

Приоритеты потоков

Каждый поток Java имеет приоритет, который помогает операционной системе определять порядок, в котором запланированы потоки.

Приоритеты потоков Java находятся в диапазоне между MIN_PRIORITY (константа 1) и MAX_PRIORITY (константа 10). По умолчанию каждому потоку присваивается приоритет NORM_PRIORITY (константа 5).

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

Создайте поток, реализуя работающий интерфейс

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

Шаг 1

В качестве первого шага вам необходимо реализовать метод run (), предоставляемый интерфейсом Runnable . Этот метод обеспечивает точку входа для потока, и вы поместите всю свою бизнес-логику в этот метод. Ниже приведен простой синтаксис метода run ():

public void run( )

Шаг 2

На втором этапе вы создадите экземпляр объекта Thread, используя следующий конструктор:

Thread(Runnable threadObj, String threadName);

Где threadObj — это экземпляр класса, который реализует интерфейс Runnable, а threadName — это имя, данное новому потоку.

Шаг 3

Как только объект Thread создан, вы можете запустить его, вызвав метод start () , который выполняет вызов метода run (). Ниже приведен простой синтаксис метода start ():

void start();

пример

Вот пример, который создает новый поток и запускает его:

Live Demo

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;

   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {
      
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo("Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo("Thread-2");
      R2.start();
   }   
}

Это даст следующий результат —

Выход

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Создать поток, расширяя класс потока

Второй способ создания потока — это создание нового класса, расширяющего класс Thread, с помощью следующих двух простых шагов. Этот подход обеспечивает большую гибкость в обработке нескольких потоков, созданных с использованием доступных методов в классе Thread.

Шаг 1

Вам нужно будет переопределить метод run (), доступный в классе Thread. Этот метод обеспечивает точку входа для потока, и вы поместите всю свою бизнес-логику в этот метод. Ниже приведен простой синтаксис метода run ():

public void run( )

Шаг 2

После создания объекта Thread его можно запустить, вызвав метод start () , который выполняет вызов метода run (). Ниже приведен простой синтаксис метода start ():

void start( );

пример

Вот предыдущая программа, переписанная для расширения темы —

Live Demo

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {

         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo("Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo("Thread-2");
      T2.start();
   }   
}

Это даст следующий результат —

Выход

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Параллелизм Java — настройка среды

В этой главе мы обсудим различные аспекты настройки благоприятной среды для Java.

Настройка локальной среды

Если вы все еще хотите настроить свою среду для языка программирования Java, то в этом разделе вы узнаете, как загрузить и настроить Java на вашем компьютере. Ниже приведены шаги по настройке среды.

Java SE находится в свободном доступе по ссылке Скачать Java . Вы можете скачать версию на основе вашей операционной системы.

Следуйте инструкциям для загрузки Java и запуска .exe для установки Java на вашем компьютере. После того, как вы установили Java на свой компьютер, вам нужно будет установить переменные окружения, чтобы они указывали на правильные каталоги установки —

Настройка пути для Windows

Предполагая, что вы установили Java в каталог c: \ Program Files \ java \ jdk

  • Щелкните правой кнопкой мыши «Мой компьютер» и выберите «Свойства».

  • Нажмите кнопку «Переменные среды» на вкладке «Дополнительно».

  • Теперь измените переменную Path, чтобы она также содержала путь к исполняемому файлу Java. Например, если в настоящий момент путь задан как «C: \ WINDOWS \ SYSTEM32», измените ваш путь на «C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ java \ jdk \ bin».

Щелкните правой кнопкой мыши «Мой компьютер» и выберите «Свойства».

Нажмите кнопку «Переменные среды» на вкладке «Дополнительно».

Теперь измените переменную Path, чтобы она также содержала путь к исполняемому файлу Java. Например, если в настоящий момент путь задан как «C: \ WINDOWS \ SYSTEM32», измените ваш путь на «C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ java \ jdk \ bin».

Настройка пути для Linux, UNIX, Solaris, FreeBSD

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

Например, если вы используете bash в качестве оболочки, вы добавили бы следующую строку в конец вашего .bashrc: export PATH = / path / to / java: $ PATH ‘

Популярные редакторы Java

Для написания ваших программ на Java вам понадобится текстовый редактор. На рынке доступны еще более сложные IDE. Но сейчас вы можете рассмотреть один из следующих —

  • Блокнот — на компьютере с Windows вы можете использовать любой простой текстовый редактор, например Блокнот (рекомендуется для этого урока), TextPad.

  • Netbeans — Java IDE с открытым исходным кодом, который можно загрузить по адресу https://netbeans.org/index.html .

  • Eclipse — Java IDE, разработанная сообществом open source eclipse и может быть загружена с https://www.eclipse.org/ .

Блокнот — на компьютере с Windows вы можете использовать любой простой текстовый редактор, например Блокнот (рекомендуется для этого урока), TextPad.

Netbeans — Java IDE с открытым исходным кодом, который можно загрузить по адресу https://netbeans.org/index.html .

Eclipse — Java IDE, разработанная сообществом open source eclipse и может быть загружена с https://www.eclipse.org/ .

Параллелизм Java — основные операции

Core Java обеспечивает полный контроль над многопоточной программой. Вы можете разработать многопоточную программу, которую можно приостановить, возобновить или полностью остановить в соответствии с вашими требованиями. Существуют различные статические методы, которые вы можете использовать в объектах потоков для управления их поведением. В следующей таблице перечислены эти методы —

Sr.No. Метод и описание
1

public void suspend ()

Этот метод переводит поток в состояние ожидания и может быть возобновлен с помощью метода resume ().

2

общественная недействительная остановка ()

Этот метод полностью останавливает поток.

3

общедоступное резюме ()

Этот метод возобновляет поток, который был приостановлен с помощью метода suspend ().

4

public void wait ()

Заставляет текущий поток ждать, пока другой поток не вызовет notify ().

5

public void notify ()

Просыпается один поток, который ожидает на мониторе этого объекта.

public void suspend ()

Этот метод переводит поток в состояние ожидания и может быть возобновлен с помощью метода resume ().

общественная недействительная остановка ()

Этот метод полностью останавливает поток.

общедоступное резюме ()

Этот метод возобновляет поток, который был приостановлен с помощью метода suspend ().

public void wait ()

Заставляет текущий поток ждать, пока другой поток не вызовет notify ().

public void notify ()

Просыпается один поток, который ожидает на мониторе этого объекта.

Имейте в виду, что в последних версиях Java не рекомендуется использовать методы suspend (), resume () и stop (), поэтому вам необходимо использовать доступные альтернативы.

пример

Live Demo

class RunnableDemo implements Runnable {
   public Thread t;
   private String threadName;
   boolean suspended = false;

   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );

      try {
         
         for(int i = 10; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);

            // Let the thread sleep for a while.
            Thread.sleep(300);

            synchronized(this) {
               
               while(suspended) {
                  wait();
               }
            }
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
   
   void suspend() {
      suspended = true;
   }
   
   synchronized void resume() {
      suspended = false;
      notify();
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo("Thread-1");
      R1.start();

      RunnableDemo R2 = new RunnableDemo("Thread-2");
      R2.start();

      try {
         Thread.sleep(1000);
         R1.suspend();
         System.out.println("Suspending First Thread");
         Thread.sleep(1000);
         R1.resume();
         System.out.println("Resuming First Thread");
         
         R2.suspend();
         System.out.println("Suspending thread Two");
         Thread.sleep(1000);
         R2.resume();
         System.out.println("Resuming thread Two");
      } catch (InterruptedException e) {
         System.out.println("Main thread Interrupted");
      } try {
         System.out.println("Waiting for threads to finish.");
         R1.t.join();
         R2.t.join();
      } catch (InterruptedException e) {
         System.out.println("Main thread Interrupted");
      }
      System.out.println("Main thread exiting.");
   }
}

Вышеуказанная программа производит следующий вывод —

Выход

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 10
Running Thread-2
Thread: Thread-2, 10
Thread: Thread-1, 9
Thread: Thread-2, 9
Thread: Thread-1, 8
Thread: Thread-2, 8
Thread: Thread-1, 7
Thread: Thread-2, 7
Suspending First Thread
Thread: Thread-2, 6
Thread: Thread-2, 5
Thread: Thread-2, 4
Resuming First Thread
Suspending thread Two
Thread: Thread-1, 6
Thread: Thread-1, 5
Thread: Thread-1, 4
Thread: Thread-1, 3
Resuming thread Two
Thread: Thread-2, 3
Waiting for threads to finish.
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Main thread exiting.

Межпотоковое общение

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

Существует три простых метода и небольшая хитрость, которая делает возможным взаимодействие потоков. Все три метода перечислены ниже —

Sr.No. Метод и описание
1

public void wait ()

Заставляет текущий поток ждать, пока другой поток не вызовет notify ().

2

public void notify ()

Просыпается один поток, который ожидает на мониторе этого объекта.

3

public void notifyAll ()

Пробуждает все потоки, вызвавшие wait () для одного и того же объекта.

public void wait ()

Заставляет текущий поток ждать, пока другой поток не вызовет notify ().

public void notify ()

Просыпается один поток, который ожидает на мониторе этого объекта.

public void notifyAll ()

Пробуждает все потоки, вызвавшие wait () для одного и того же объекта.

Эти методы были реализованы как окончательные методы в Object, поэтому они доступны во всех классах. Все три метода могут быть вызваны только из синхронизированного контекста.

пример

В этом примере показано, как два потока могут общаться, используя методы wait () и notify () . Вы можете создать сложную систему, используя ту же концепцию.

Live Demo

class Chat {
   boolean flag = false;

   public synchronized void Question(String msg) {

      if (flag) {
         
         try {
            wait();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
      System.out.println(msg);
      flag = true;
      notify();
   }

   public synchronized void Answer(String msg) {

      if (!flag) {
         
         try {
            wait();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
      System.out.println(msg);
      flag = false;
      notify();
   }
}

class T1 implements Runnable {
   Chat m;
   String[] s1 = { "Hi", "How are you ?", "I am also doing fine!" };

   public T1(Chat m1) {
      this.m = m1;
      new Thread(this, "Question").start();
   }

   public void run() {
   
      for (int i = 0; i < s1.length; i++) {
         m.Question(s1[i]);
      }
   }
}

class T2 implements Runnable {
   Chat m;
   String[] s2 = { "Hi", "I am good, what about you?", "Great!" };

   public T2(Chat m2) {
      this.m = m2;
      new Thread(this, "Answer").start();
   }

   public void run() {

      for (int i = 0; i < s2.length; i++) {
         m.Answer(s2[i]);
      }
   }
}

public class TestThread {

   public static void main(String[] args) {
      Chat m = new Chat();
      new T1(m);
      new T2(m);
   }
}

Когда вышеуказанная программа выполняется и выполняется, она дает следующий результат —

Выход

Hi
Hi
How are you ?
I am good, what about you?
I am also doing fine!
Great!

Приведенный выше пример был взят и затем изменен с [https://stackoverflow.com/questions/2170520/inter-thread-communication-in-java]

Java Concurrency — Синхронизация

Пример многопоточности с синхронизацией

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

пример

Live Demo

class PrintDemo {
   
   public void printCount() {
      
      try {
         
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter   ---   "  + i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo  PD;

   ThreadDemo(String name,  PrintDemo pd) {
      threadName = name;
      PD = pd;
   }
   
   public void run() {
      
      synchronized(PD) {
         PD.printCount();
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD);
      ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD);

      T1.start();
      T2.start();

      // wait for threads to end
      try {
         T1.join();
         T2.join();
      } catch (Exception e) {
         System.out.println("Interrupted");
      }
   }
}

Это приводит к тому же результату каждый раз, когда вы запускаете эту программу —

Выход

Starting Thread - 1
Starting Thread - 2
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.

Параллелизм Java — тупик

Deadlock описывает ситуацию, когда два или более потоков заблокированы навсегда, ожидая друг друга. Взаимная блокировка возникает, когда нескольким потокам требуются одинаковые блокировки, но они получают их в другом порядке. Многопоточная программа на Java может страдать из-за тупиковой ситуации, поскольку ключевое слово synchronized заставляет исполняющий поток блокировать при ожидании блокировки или монитора, связанного с указанным объектом. Вот пример.

пример

Live Demo

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();
   
   public static void main(String args[]) {
      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }
   
   private static class ThreadDemo1 extends Thread {
   
      public void run() {
      
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");

            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");

            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }

   private static class ThreadDemo2 extends Thread {
   
      public void run() {
      
         synchronized (Lock2) {
            System.out.println("Thread 2: Holding lock 2...");
            
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            
            synchronized (Lock1) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   } 
}

Когда вы компилируете и запускаете вышеупомянутую программу, вы обнаруживаете ситуацию взаимоблокировки, и после нее выдается результат, полученный программой:

Выход

Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...

Вышеприведенная программа будет зависать вечно, потому что ни один из потоков не находится в положении для продолжения и ждет, пока друг друга снимают блокировку, поэтому вы можете выйти из программы, нажав CTRL + C.

Пример тупикового решения

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

пример

Live Demo

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();
   
   public static void main(String args[]) {
      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }
   
   private static class ThreadDemo1 extends Thread {
   
      public void run() {
         
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");
            
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");

            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }

   private static class ThreadDemo2 extends Thread {
      
      public void run() {
         
         synchronized (Lock1) {
            System.out.println("Thread 2: Holding lock 1...");
           
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 2...");

            synchronized (Lock2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   } 
}

Таким образом, просто изменение порядка блокировок не позволяет программе войти в тупиковую ситуацию и завершается следующим результатом:

Выход

Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...

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

Параллелизм Java — класс ThreadLocal

Класс ThreadLocal используется для создания локальных переменных потока, которые могут быть прочитаны и записаны только одним потоком. Например, если два потока обращаются к коду, имеющему ссылку на одну и ту же переменную threadLocal, то каждый поток не увидит никаких изменений в переменной threadLocal, выполненных другим потоком.

ThreadLocal Методы

Ниже приведен список важных методов, доступных в классе ThreadLocal.

Sr.No. Метод и описание
1

public T get ()

Возвращает значение в копии текущего потока этой локальной переменной потока.

2

Защищенный T initialValue ()

Возвращает «начальное значение» текущего потока для этой локальной переменной потока.

3

public void remove ()

Удаляет значение текущего потока для этой локальной переменной потока.

4

открытый набор пустот (значение T)

Устанавливает копию текущего потока этой локальной переменной потока в указанное значение.

public T get ()

Возвращает значение в копии текущего потока этой локальной переменной потока.

Защищенный T initialValue ()

Возвращает «начальное значение» текущего потока для этой локальной переменной потока.

public void remove ()

Удаляет значение текущего потока для этой локальной переменной потока.

открытый набор пустот (значение T)

Устанавливает копию текущего потока этой локальной переменной потока в указанное значение.

пример

Следующая программа TestThread демонстрирует некоторые из этих методов класса ThreadLocal. Здесь мы использовали две переменные счетчика, одна из которых является нормальной переменной, а другая — ThreadLocal.

Live Demo

class RunnableDemo implements Runnable {
   int counter;
   ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<Integer>();

   public void run() {     
      counter++;

      if(threadLocalCounter.get() != null) {
         threadLocalCounter.set(threadLocalCounter.get().intValue() + 1);
      } else {
         threadLocalCounter.set(0);
      }
      System.out.println("Counter: " + counter);
      System.out.println("threadLocalCounter: " + threadLocalCounter.get());
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo commonInstance = new RunnableDemo();

      Thread t1 = new Thread(commonInstance);
      Thread t2 = new Thread(commonInstance);
      Thread t3 = new Thread(commonInstance);
      Thread t4 = new Thread(commonInstance);

      t1.start();
      t2.start();
      t3.start();
      t4.start();

      // wait for threads to end
      try {
         t1.join();
         t2.join();
         t3.join();
         t4.join();
      } catch (Exception e) {
         System.out.println("Interrupted");
      }
   }
}

Это даст следующий результат.

Выход

Counter: 1
threadLocalCounter: 0
Counter: 2
threadLocalCounter: 0
Counter: 3
threadLocalCounter: 0
Counter: 4
threadLocalCounter: 0

Вы можете видеть, что значение счетчика увеличивается каждым потоком, но threadLocalCounter остается 0 для каждого потока.

Класс ThreadLocalRandom

Java.util.concurrent.ThreadLocalRandom — это служебный класс, введенный начиная с jdk 1.7 и более полезный, когда для генерации случайных чисел требуется несколько потоков или заданий ForkJoinTasks. Это улучшает производительность и имеет меньше конфликтов, чем метод Math.random ().

ThreadLocalRandom Методы

Ниже приведен список важных методов, доступных в классе ThreadLocalRandom.

Sr.No. Метод и описание
1

общедоступная статическая ThreadLocalRandom current ()

Возвращает текущий поток ThreadLocalRandom.

2

защищенный int следующий (int биты)

Создает следующее псевдослучайное число.

3

public double nextDouble (double n)

Возвращает псевдослучайное, равномерно распределенное двойное значение между 0 (включительно) и указанным значением (исключая).

4

public double nextDouble (двойной минимум, двойная граница)

Возвращает псевдослучайное, равномерно распределенное значение между заданным наименьшим значением (включительно) и связанным (исключение).

5

public int nextInt (минимум int, привязанный int)

Возвращает псевдослучайное, равномерно распределенное значение между заданным наименьшим значением (включительно) и связанным (исключение).

6

public long nextLong (long n)

Возвращает псевдослучайное, равномерно распределенное значение между 0 (включительно) и указанным значением (исключая).

7

public long nextLong (длинный, длинный)

Возвращает псевдослучайное, равномерно распределенное значение между заданным наименьшим значением (включительно) и связанным (исключение).

8

public void setSeed (long seed)

Выдает UnsupportedOperationException.

общедоступная статическая ThreadLocalRandom current ()

Возвращает текущий поток ThreadLocalRandom.

защищенный int следующий (int биты)

Создает следующее псевдослучайное число.

public double nextDouble (double n)

Возвращает псевдослучайное, равномерно распределенное двойное значение между 0 (включительно) и указанным значением (исключая).

public double nextDouble (двойной минимум, двойная граница)

Возвращает псевдослучайное, равномерно распределенное значение между заданным наименьшим значением (включительно) и связанным (исключение).

public int nextInt (минимум int, привязанный int)

Возвращает псевдослучайное, равномерно распределенное значение между заданным наименьшим значением (включительно) и связанным (исключение).

public long nextLong (long n)

Возвращает псевдослучайное, равномерно распределенное значение между 0 (включительно) и указанным значением (исключая).

public long nextLong (длинный, длинный)

Возвращает псевдослучайное, равномерно распределенное значение между заданным наименьшим значением (включительно) и связанным (исключение).

public void setSeed (long seed)

Выдает UnsupportedOperationException.

пример

Следующая программа TestThread демонстрирует некоторые из этих методов интерфейса Lock. Здесь мы использовали lock (), чтобы получить блокировку, и unlock (), чтобы снять блокировку.

Live Demo

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ThreadLocalRandom;

public class TestThread {
  
   public static void main(final String[] arguments) {
      System.out.println("Random Integer: " + new Random().nextInt());  
      System.out.println("Seeded Random Integer: " + new Random(15).nextInt());  
      System.out.println(
         "Thread Local Random Integer: " + ThreadLocalRandom.current().nextInt());
      
      final ThreadLocalRandom random = ThreadLocalRandom.current();  
      random.setSeed(15); //exception will come as seeding is not allowed in ThreadLocalRandom.
      System.out.println("Seeded Thread Local Random Integer: " + random.nextInt());  
   }
}

Это даст следующий результат.

Выход

Random Integer: 1566889198
Seeded Random Integer: -1159716814
Thread Local Random Integer: 358693993
Exception in thread "main" java.lang.UnsupportedOperationException
        at java.util.concurrent.ThreadLocalRandom.setSeed(Unknown Source)
        at TestThread.main(TestThread.java:21)

Здесь мы использовали классы ThreadLocalRandom и Random для получения случайных чисел.

Параллелизм Java — интерфейс блокировки

Интерфейс java.util.concurrent.locks.Lock используется в качестве механизма синхронизации потоков, аналогичного синхронизированным блокам. Новый механизм блокировки является более гибким и предоставляет больше возможностей, чем синхронизированный блок. Основные различия между замком и синхронизированным блоком следующие:

  • Гарантия последовательности — Синхронизированный блок не дает никакой гарантии последовательности, в которой ожидающему потоку будет предоставлен доступ. Интерфейс блокировки обрабатывает это.

  • Нет тайм-аута. Синхронизированный блок не имеет опции тайм-аута, если блокировка не предоставлена. Интерфейс блокировки предоставляет такую ​​возможность.

  • Одиночный метод — Синхронизированный блок должен полностью содержаться в одном методе, в то время как методы интерфейса блокировки lock () и unlock () могут вызываться в разных методах.

Гарантия последовательности — Синхронизированный блок не дает никакой гарантии последовательности, в которой ожидающему потоку будет предоставлен доступ. Интерфейс блокировки обрабатывает это.

Нет тайм-аута. Синхронизированный блок не имеет опции тайм-аута, если блокировка не предоставлена. Интерфейс блокировки предоставляет такую ​​возможность.

Одиночный метод — Синхронизированный блок должен полностью содержаться в одном методе, в то время как методы интерфейса блокировки lock () и unlock () могут вызываться в разных методах.

Методы блокировки

Ниже приведен список важных методов, доступных в классе Lock.

Sr.No. Метод и описание
1

общедоступная блокировка недействительности ()

Приобретает замок.

2

public void lockInterruptibly ()

Получает блокировку, если текущий поток не прерывается.

3

публичное состояние newCondition ()

Возвращает новый экземпляр Condition, связанный с этим экземпляром Lock.

4

public boolean tryLock ()

Получает блокировку, только если она свободна на момент вызова.

5

public boolean tryLock ()

Получает блокировку, только если она свободна на момент вызова.

6

public boolean tryLock (долгое время, модуль TimeUnit)

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

7

общедоступная разблокировка void ()

Снимает блокировку.

общедоступная блокировка недействительности ()

Приобретает замок.

public void lockInterruptibly ()

Получает блокировку, если текущий поток не прерывается.

публичное состояние newCondition ()

Возвращает новый экземпляр Condition, связанный с этим экземпляром Lock.

public boolean tryLock ()

Получает блокировку, только если она свободна на момент вызова.

public boolean tryLock ()

Получает блокировку, только если она свободна на момент вызова.

public boolean tryLock (долгое время, модуль TimeUnit)

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

общедоступная разблокировка void ()

Снимает блокировку.

пример

Следующая программа TestThread демонстрирует некоторые из этих методов интерфейса Lock. Здесь мы использовали lock (), чтобы получить блокировку, и unlock (), чтобы снять блокировку.

Live Demo

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class PrintDemo {
   private final Lock queueLock = new ReentrantLock();

   public void print() {
      queueLock.lock();

      try {
         Long duration = (long) (Math.random() * 10000);
         System.out.println(Thread.currentThread().getName() 
            + "  Time Taken " + (duration / 1000) + " seconds.");
         Thread.sleep(duration);
      } catch (InterruptedException e) {
         e.printStackTrace();
      } finally {
         System.out.printf(
            "%s printed the document successfully.\n", Thread.currentThread().getName());
         queueLock.unlock();
      }
   }
}

class ThreadDemo extends Thread {
   PrintDemo  printDemo;

   ThreadDemo(String name,  PrintDemo printDemo) {
      super(name);
      this.printDemo = printDemo;
   }   

   @Override
   public void run() {
      System.out.printf(
         "%s starts printing a document\n", Thread.currentThread().getName());
      printDemo.print();
   }
}

public class TestThread {

   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo t1 = new ThreadDemo("Thread - 1 ", PD);
      ThreadDemo t2 = new ThreadDemo("Thread - 2 ", PD);
      ThreadDemo t3 = new ThreadDemo("Thread - 3 ", PD);
      ThreadDemo t4 = new ThreadDemo("Thread - 4 ", PD);

      t1.start();
      t2.start();
      t3.start();
      t4.start();
   }
}

Это даст следующий результат.

Выход

Thread - 1  starts printing a document
Thread - 4  starts printing a document
Thread - 3  starts printing a document
Thread - 2  starts printing a document
Thread - 1   Time Taken 4 seconds.
Thread - 1  printed the document successfully.
Thread - 4   Time Taken 3 seconds.
Thread - 4  printed the document successfully.
Thread - 3   Time Taken 5 seconds.
Thread - 3  printed the document successfully.
Thread - 2   Time Taken 4 seconds.
Thread - 2  printed the document successfully.

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

Параллелизм Java — интерфейс ReadWriteLock

Интерфейс java.util.concurrent.locks.ReadWriteLock позволяет читать несколько потоков одновременно, но одновременно может писать только один поток.

  • Блокировка чтения — если ни один поток не заблокировал ReadWriteLock для записи, то несколько потоков могут получить доступ к блокировке чтения.

  • Блокировка записи — если ни один поток не читает или не пишет, то один поток может получить доступ к блокировке записи.

Блокировка чтения — если ни один поток не заблокировал ReadWriteLock для записи, то несколько потоков могут получить доступ к блокировке чтения.

Блокировка записи — если ни один поток не читает или не пишет, то один поток может получить доступ к блокировке записи.

Методы блокировки

Ниже приведен список важных методов, доступных в классе Lock.

Sr.No. Метод и описание
1

public Lock readLock ()

Возвращает блокировку, используемую для чтения.

2

открытый замок writeLock ()

Возвращает блокировку, использованную для записи.

public Lock readLock ()

Возвращает блокировку, используемую для чтения.

открытый замок writeLock ()

Возвращает блокировку, использованную для записи.

пример

Следующая программа TestThread демонстрирует эти методы интерфейса ReadWriteLock. Здесь мы использовали readlock () для получения блокировки чтения и writeLock () для получения блокировки записи.

Live Demo

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestThread {
   private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
   private static String message = "a";

   public static void main(String[] args) throws InterruptedException {
      Thread t1 = new Thread(new WriterA());
      t1.setName("Writer A");
      
      Thread t2 = new Thread(new WriterB());
      t2.setName("Writer B");
      
      Thread t3 = new Thread(new Reader());
      t3.setName("Reader");
      t1.start();
      t2.start();
      t3.start();
      t1.join();
      t2.join();
      t3.join();
   }

   static class Reader implements Runnable {

      public void run() {
         
         if(lock.isWriteLocked()) {
            System.out.println("Write Lock Present.");
         }
         lock.readLock().lock();

         try {
            Long duration = (long) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() 
               + "  Time Taken " + (duration / 1000) + " seconds.");
            Thread.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            System.out.println(Thread.currentThread().getName() +": "+ message );
            lock.readLock().unlock();
         }
      }
   }

   static class WriterA implements Runnable {

      public void run() {
         lock.writeLock().lock();
         
         try {
            Long duration = (long) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() 
               + "  Time Taken " + (duration / 1000) + " seconds.");
            Thread.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            message = message.concat("a");
            lock.writeLock().unlock();
         }
      }
   }

   static class WriterB implements Runnable {

      public void run() {
         lock.writeLock().lock();
         
         try {
            Long duration = (long) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() 
               + "  Time Taken " + (duration / 1000) + " seconds.");
            Thread.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            message = message.concat("b");
            lock.writeLock().unlock();
         }
      }
   }
}

Это даст следующий результат.

Выход

Writer A  Time Taken 6 seconds.
Write Lock Present.
Writer B  Time Taken 2 seconds.
Reader  Time Taken 0 seconds.
Reader: aab

Параллелизм Java — интерфейс условий

Интерфейс java.util.concurrent.locks.Condition обеспечивает возможность потока приостановить его выполнение до тех пор, пока данное условие не станет истинным. Объект Condition обязательно связан с Lock и должен быть получен с помощью метода newCondition ().

Методы условий

Ниже приведен список важных методов, доступных в классе Condition.

Sr.No. Метод и описание
1

публичное недействительное ожидание ()

Заставляет текущий поток ждать, пока он не будет сигнализирован или прерван.

2

public boolean await (долгое время, единица времени)

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

3

публичные долгожданныеNanos (long nanosTimeout)

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

4

Публичный долгожданный бесперебойно ()

Заставляет текущий поток ждать, пока он не будет сигнализирован.

5

public long awaitUntil ()

Заставляет текущий поток ждать, пока он не будет сигнализирован или прерван, или пока не истечет указанный крайний срок.

6

публичный пустой сигнал ()

Просыпается одна ожидающая нить.

7

public void signalAll ()

Просыпается все ожидающие темы.

публичное недействительное ожидание ()

Заставляет текущий поток ждать, пока он не будет сигнализирован или прерван.

public boolean await (долгое время, единица времени)

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

публичные долгожданныеNanos (long nanosTimeout)

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

Публичный долгожданный бесперебойно ()

Заставляет текущий поток ждать, пока он не будет сигнализирован.

public long awaitUntil ()

Заставляет текущий поток ждать, пока он не будет сигнализирован или прерван, или пока не истечет указанный крайний срок.

публичный пустой сигнал ()

Просыпается одна ожидающая нить.

public void signalAll ()

Просыпается все ожидающие темы.

пример

Следующая программа TestThread демонстрирует эти методы интерфейса Condition. Здесь мы использовали signal () для уведомления и await () для приостановки потока.

Live Demo

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestThread {

   public static void main(String[] args) throws InterruptedException {
      ItemQueue itemQueue = new ItemQueue(10);

      //Create a producer and a consumer.
      Thread producer = new Producer(itemQueue);
      Thread consumer = new Consumer(itemQueue);

      //Start both threads.
      producer.start();
      consumer.start();

      //Wait for both threads to terminate.
      producer.join();
      consumer.join();
   }

   static class ItemQueue {
      private Object[] items = null;
      private int current = 0;
      private int placeIndex = 0;
      private int removeIndex = 0;

      private final Lock lock;
      private final Condition isEmpty;
      private final Condition isFull;

      public ItemQueue(int capacity) {
         this.items = new Object[capacity];
         lock = new ReentrantLock();
         isEmpty = lock.newCondition();
         isFull = lock.newCondition();
      }

      public void add(Object item) throws InterruptedException {
         lock.lock();

         while(current >= items.length)
            isFull.await();

         items[placeIndex] = item;
         placeIndex = (placeIndex + 1) % items.length;
         ++current;

         //Notify the consumer that there is data available.
         isEmpty.signal();
         lock.unlock();
      }

      public Object remove() throws InterruptedException {
         Object item = null;

         lock.lock();

         while(current <= 0) {
            isEmpty.await();
         }
         item = items[removeIndex];
         removeIndex = (removeIndex + 1) % items.length;
         --current;

         //Notify the producer that there is space available.
         isFull.signal();
         lock.unlock();

         return item;
      }

      public boolean isEmpty() {
         return (items.length == 0);
      }
   }

   static class Producer extends Thread {
      private final ItemQueue queue;
      
      public Producer(ItemQueue queue) {
         this.queue = queue;
      }

      @Override
      public void run() {
         String[] numbers =
            {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};

         try {
            
            for(String number: numbers) {
               System.out.println("[Producer]: " + number);
            }
            queue.add(null);
         } catch (InterruptedException ex) {
            ex.printStackTrace();
         } 
      }
   }

   static class Consumer extends Thread {
      private final ItemQueue queue;
      
      public Consumer(ItemQueue queue) {
         this.queue = queue;
      }

      @Override
      public void run() {
         
         try {
            
            do {
               Object number = queue.remove();
               System.out.println("[Consumer]: " + number);

               if(number == null) {
                  return;
               }
            } while(!queue.isEmpty());
         } catch (InterruptedException ex) {
            ex.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

[Producer]: 1
[Producer]: 2
[Producer]: 3
[Producer]: 4
[Producer]: 5
[Producer]: 6
[Producer]: 7
[Producer]: 8
[Producer]: 9
[Producer]: 10
[Producer]: 11
[Producer]: 12
[Consumer]: null

Параллелизм Java — класс AtomicInteger

Класс java.util.concurrent.atomic.AtomicInteger предоставляет операции с базовым значением int, которые могут быть прочитаны и записаны атомарно, а также содержит расширенные атомарные операции. AtomicInteger поддерживает атомарные операции с базовой переменной int. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Методы AtomicInteger

Ниже приведен список важных методов, доступных в классе AtomicInteger.

Sr.No. Метод и описание
1

public int addAndGet (int delta)

Атомно добавляет данное значение к текущему значению.

2

public boolean compareAndSet (ожидаемое int, обновление int)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

3

public int decmentAndGet ()

Атомно уменьшает на единицу текущее значение.

4

public double doubleValue ()

Возвращает значение указанного числа в виде двойного числа.

5

публичный float floatValue ()

Возвращает значение указанного числа в виде числа с плавающей запятой.

6

public int get ()

Получает текущее значение.

7

public int getAndAdd (int delta)

Atomiclly добавляет данное значение к текущему значению.

8

public int getAndDecrement ()

Атомно уменьшает на единицу текущее значение.

9

public int getAndIncrement ()

Атомно увеличивает на единицу текущее значение.

10

public int getAndSet (int newValue)

Атомно устанавливает заданное значение и возвращает старое значение.

11

public int incrementAndGet ()

Атомно увеличивает на единицу текущее значение.

12

public int intValue ()

Возвращает значение указанного числа в виде целого числа.

13

public void lazySet (int newValue)

В конце концов устанавливается на заданное значение.

14

public long longValue ()

Возвращает значение указанного числа в виде long.

15

открытый набор void (int newValue)

Устанавливается на заданное значение.

16

public String toString ()

Возвращает строковое представление текущего значения.

17

public boolean weakCompareAndSet (ожидаемое, обновление int)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

public int addAndGet (int delta)

Атомно добавляет данное значение к текущему значению.

public boolean compareAndSet (ожидаемое int, обновление int)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

public int decmentAndGet ()

Атомно уменьшает на единицу текущее значение.

public double doubleValue ()

Возвращает значение указанного числа в виде двойного числа.

публичный float floatValue ()

Возвращает значение указанного числа в виде числа с плавающей запятой.

public int get ()

Получает текущее значение.

public int getAndAdd (int delta)

Atomiclly добавляет данное значение к текущему значению.

public int getAndDecrement ()

Атомно уменьшает на единицу текущее значение.

public int getAndIncrement ()

Атомно увеличивает на единицу текущее значение.

public int getAndSet (int newValue)

Атомно устанавливает заданное значение и возвращает старое значение.

public int incrementAndGet ()

Атомно увеличивает на единицу текущее значение.

public int intValue ()

Возвращает значение указанного числа в виде целого числа.

public void lazySet (int newValue)

В конце концов устанавливается на заданное значение.

public long longValue ()

Возвращает значение указанного числа в виде long.

открытый набор void (int newValue)

Устанавливается на заданное значение.

public String toString ()

Возвращает строковое представление текущего значения.

public boolean weakCompareAndSet (ожидаемое, обновление int)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

пример

Следующая программа TestThread показывает небезопасную реализацию счетчика в среде на основе потоков.

Live Demo

public class TestThread {

   static class Counter {
      private int c = 0;

      public void increment() {
         c++;
      }

      public int value() {
         return c;
      }
   }
   
   public static void main(final String[] arguments) throws InterruptedException {
      final Counter counter = new Counter();
      
      //1000 threads
      for(int i = 0; i < 1000 ; i++) {
         
         new Thread(new Runnable() {
            
            public void run() {
               counter.increment();
            }
         }).start(); 
      }  
      Thread.sleep(6000);
      System.out.println("Final number (should be 1000): " + counter.value());
   }  
}

Это может привести к следующему результату в зависимости от скорости компьютера и чередования потоков.

Выход

Final number (should be 1000): 1000

пример

Следующая программа TestThread показывает безопасную реализацию счетчика с использованием AtomicInteger в среде на основе потоков.

Live Demo

import java.util.concurrent.atomic.AtomicInteger;

public class TestThread {

   static class Counter {
      private AtomicInteger c = new AtomicInteger(0);

      public void increment() {
         c.getAndIncrement();
      }

      public int value() {
         return c.get();
      }
   }
   
   public static void main(final String[] arguments) throws InterruptedException {
      final Counter counter = new Counter();
      
      //1000 threads
      for(int i = 0; i < 1000 ; i++) {

         new Thread(new Runnable() {
            public void run() {
               counter.increment();
            }
         }).start(); 
      }  
      Thread.sleep(6000);
      System.out.println("Final number (should be 1000): " + counter.value());
   }
}

Это даст следующий результат.

Выход

Final number (should be 1000): 1000

Параллелизм Java — класс AtomicLong

Класс java.util.concurrent.atomic.AtomicLong обеспечивает операции с базовым длинным значением, которые могут быть прочитаны и записаны атомарно, а также содержит расширенные атомарные операции. AtomicLong поддерживает атомарные операции с базовой переменной long. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Методы AtomicLong

Ниже приведен список важных методов, доступных в классе AtomicLong.

Sr.No. Метод и описание
1

public long addAndGet (длинная дельта)

Атомно добавляет данное значение к текущему значению.

2

public boolean compareAndSet (долгое ожидание, долгое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

3

общедоступный long декремент AndGet ()

Атомно уменьшает на единицу текущее значение.

4

public double doubleValue ()

Возвращает значение указанного числа в виде двойного числа.

5

публичный float floatValue ()

Возвращает значение указанного числа в виде числа с плавающей запятой.

6

публичный длинный get ()

Получает текущее значение.

7

public long getAndAdd (длинная дельта)

Atomiclly добавляет данное значение к текущему значению.

8

public long getAndDecrement ()

Атомно уменьшает на единицу текущее значение.

9

public long getAndIncrement ()

Атомно увеличивает на единицу текущее значение.

10

public long getAndSet (long newValue)

Атомно устанавливает заданное значение и возвращает старое значение.

11

public long incrementAndGet ()

Атомно увеличивает на единицу текущее значение.

12

public int intValue ()

Возвращает значение указанного числа в виде целого числа.

13

public void lazySet (long newValue)

В конце концов устанавливается на заданное значение.

14

public long longValue ()

Возвращает значение указанного числа в виде long.

15

открытый набор void (long newValue)

Устанавливается на заданное значение.

16

public String toString ()

Возвращает строковое представление текущего значения.

17

public boolean weakCompareAndSet (долгое ожидание, долгое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

public long addAndGet (длинная дельта)

Атомно добавляет данное значение к текущему значению.

public boolean compareAndSet (долгое ожидание, долгое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

общедоступный long декремент AndGet ()

Атомно уменьшает на единицу текущее значение.

public double doubleValue ()

Возвращает значение указанного числа в виде двойного числа.

публичный float floatValue ()

Возвращает значение указанного числа в виде числа с плавающей запятой.

публичный длинный get ()

Получает текущее значение.

public long getAndAdd (длинная дельта)

Atomiclly добавляет данное значение к текущему значению.

public long getAndDecrement ()

Атомно уменьшает на единицу текущее значение.

public long getAndIncrement ()

Атомно увеличивает на единицу текущее значение.

public long getAndSet (long newValue)

Атомно устанавливает заданное значение и возвращает старое значение.

public long incrementAndGet ()

Атомно увеличивает на единицу текущее значение.

public int intValue ()

Возвращает значение указанного числа в виде целого числа.

public void lazySet (long newValue)

В конце концов устанавливается на заданное значение.

public long longValue ()

Возвращает значение указанного числа в виде long.

открытый набор void (long newValue)

Устанавливается на заданное значение.

public String toString ()

Возвращает строковое представление текущего значения.

public boolean weakCompareAndSet (долгое ожидание, долгое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение совпадает с ожидаемым значением.

пример

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

Live Demo

import java.util.concurrent.atomic.AtomicLong;

public class TestThread {

   static class Counter {
      private AtomicLong c = new AtomicLong(0);

      public void increment() {
         c.getAndIncrement();
      }

      public long value() {
         return c.get();
      }
   }

   public static void main(final String[] arguments) throws InterruptedException {
      final Counter counter = new Counter();
      
      //1000 threads
      for(int i = 0; i < 1000 ; i++) {
         
         new Thread(new Runnable() {
            
            public void run() {
               counter.increment();
            }
         }).start();	
      }
      Thread.sleep(6000);			   		  
      System.out.println("Final number (should be 1000): " + counter.value());
   }
}

Это даст следующий результат.

Выход

Final number (should be 1000): 1000

Параллелизм Java — класс AtomicBoolean

Класс java.util.concurrent.atomic.AtomicBoolean предоставляет операции с базовым логическим значением, которое может быть прочитано и записано атомарно, а также содержит расширенные атомарные операции. AtomicBoolean поддерживает атомарные операции с базовой логической переменной. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Атомно-булевы методы

Ниже приведен список важных методов, доступных в классе AtomicBoolean.

Sr.No. Метод и описание
1

public boolean compareAndSet (логическое ожидание, логическое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

2

public boolean get ()

Возвращает текущее значение.

3

public boolean getAndSet (логическое новое значение)

Атомно устанавливается на заданное значение и возвращает предыдущее значение.

4

public void lazySet (логическое новое значение)

В конце концов устанавливается на заданное значение.

5

открытый набор void (логическое значение newValue)

Безусловно устанавливается на заданное значение.

6

public String toString ()

Возвращает строковое представление текущего значения.

7

public boolean weakCompareAndSet (логическое ожидание, логическое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

public boolean compareAndSet (логическое ожидание, логическое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

public boolean get ()

Возвращает текущее значение.

public boolean getAndSet (логическое новое значение)

Атомно устанавливается на заданное значение и возвращает предыдущее значение.

public void lazySet (логическое новое значение)

В конце концов устанавливается на заданное значение.

открытый набор void (логическое значение newValue)

Безусловно устанавливается на заданное значение.

public String toString ()

Возвращает строковое представление текущего значения.

public boolean weakCompareAndSet (логическое ожидание, логическое обновление)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

пример

Следующая программа TestThread показывает использование переменной AtomicBoolean в среде, основанной на потоках.

Live Demo

import java.util.concurrent.atomic.AtomicBoolean;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

      new Thread("Thread 1") {

         public void run() {

            while(true) {
               System.out.println(Thread.currentThread().getName() 
                  +" Waiting for Thread 2 to set Atomic variable to true. Current value is "
                  + atomicBoolean.get());

               if(atomicBoolean.compareAndSet(true, false)) {
                  System.out.println("Done!");
                  break;
               }
            }
         };
      }.start();

      new Thread("Thread 2") {

         public void run() {
            System.out.println(Thread.currentThread().getName() +
               ", Atomic Variable: " +atomicBoolean.get()); 
            System.out.println(Thread.currentThread().getName() +
               " is setting the variable to true ");
            atomicBoolean.set(true);
            System.out.println(Thread.currentThread().getName() +
               ", Atomic Variable: " +atomicBoolean.get()); 
         };
      }.start();
   }
}

Это даст следующий результат.

Выход

Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 2, Atomic Variable: false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 2 is setting the variable to true
Thread 2, Atomic Variable: true
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Done!

Параллелизм Java — класс AtomicReference

Класс java.util.concurrent.atomic.AtomicReference предоставляет операции над базовой ссылкой на объект, которые можно читать и записывать атомарно, а также содержит расширенные атомарные операции. AtomicReference поддерживает атомарные операции с базовой переменной объекта. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Методы AtomicReference

Ниже приведен список важных методов, доступных в классе AtomicReference.

Sr.No. Метод и описание
1

public boolean compareAndSet (ожидание, обновление V)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

2

public boolean get ()

Возвращает текущее значение.

3

public boolean getAndSet (V newValue)

Атомно устанавливается на заданное значение и возвращает предыдущее значение.

4

public void lazySet (V newValue)

В конце концов устанавливается на заданное значение.

5

открытый набор void (V newValue)

Безусловно устанавливается на заданное значение.

6

public String toString ()

Возвращает строковое представление текущего значения.

7

public boolean weakCompareAndSet (ожидание, обновление V)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

public boolean compareAndSet (ожидание, обновление V)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

public boolean get ()

Возвращает текущее значение.

public boolean getAndSet (V newValue)

Атомно устанавливается на заданное значение и возвращает предыдущее значение.

public void lazySet (V newValue)

В конце концов устанавливается на заданное значение.

открытый набор void (V newValue)

Безусловно устанавливается на заданное значение.

public String toString ()

Возвращает строковое представление текущего значения.

public boolean weakCompareAndSet (ожидание, обновление V)

Атомно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение.

пример

Следующая программа TestThread показывает использование переменной AtomicReference в потоковой среде.

Live Demo

import java.util.concurrent.atomic.AtomicReference;

public class TestThread {
   private static String message = "hello";
   private static AtomicReference<String> atomicReference;

   public static void main(final String[] arguments) throws InterruptedException {
      atomicReference = new AtomicReference<String>(message);
      
      new Thread("Thread 1") {
         
         public void run() {
            atomicReference.compareAndSet(message, "Thread 1");
            message = message.concat("-Thread 1!");
         };
      }.start();

      System.out.println("Message is: " + message);
      System.out.println("Atomic Reference of Message is: " + atomicReference.get());
   }
}

Это даст следующий результат.

Выход

Message is: hello
Atomic Reference of Message is: Thread 1

Параллелизм Java — класс AtomicIntegerArray

Класс java.util.concurrent.atomic.AtomicIntegerArray предоставляет операции с базовым массивом int, которые можно читать и записывать атомарно, а также содержит расширенные атомарные операции. AtomicIntegerArray поддерживает атомарные операции с базовой переменной массива int. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Методы AtomicIntegerArray

Ниже приведен список важных методов, доступных в классе AtomicIntegerArray.

Sr.No. Метод и описание
1

public int addAndGet (int i, int delta)

Атомно добавляет данное значение к элементу по индексу i.

2

public boolean compareAndSet (int i, int Ожидается, int обновление)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

3

public int decmentAndGet (int i)

Атомно уменьшает на единицу элемент с индексом i.

4

public int get (int i)

Получает текущее значение в позиции i.

5

public int getAndAdd (int i, int delta)

Атомно добавляет данное значение к элементу по индексу i.

6

public int getAndDecrement (int i)

Атомно уменьшает на единицу элемент с индексом i.

7

public int getAndIncrement (int i)

Атомно увеличивает на единицу элемент с индексом i.

8

public int getAndSet (int i, int newValue)

Атомно устанавливает элемент в позиции i на заданное значение и возвращает старое значение.

9

public int incrementAndGet (int i)

Атомно увеличивает на единицу элемент с индексом i.

10

public void lazySet (int i, int newValue)

В конце концов устанавливает элемент в позиции i на заданное значение.

11

public int length ()

Возвращает длину массива.

12

открытый набор void (int i, int newValue)

Устанавливает элемент в позиции i в указанное значение.

13

public String toString ()

Возвращает строковое представление текущих значений массива.

14

public boolean weakCompareAndSet (int i, int Ожидается, int обновление)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

public int addAndGet (int i, int delta)

Атомно добавляет данное значение к элементу по индексу i.

public boolean compareAndSet (int i, int Ожидается, int обновление)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

public int decmentAndGet (int i)

Атомно уменьшает на единицу элемент с индексом i.

public int get (int i)

Получает текущее значение в позиции i.

public int getAndAdd (int i, int delta)

Атомно добавляет данное значение к элементу по индексу i.

public int getAndDecrement (int i)

Атомно уменьшает на единицу элемент с индексом i.

public int getAndIncrement (int i)

Атомно увеличивает на единицу элемент с индексом i.

public int getAndSet (int i, int newValue)

Атомно устанавливает элемент в позиции i на заданное значение и возвращает старое значение.

public int incrementAndGet (int i)

Атомно увеличивает на единицу элемент с индексом i.

public void lazySet (int i, int newValue)

В конце концов устанавливает элемент в позиции i на заданное значение.

public int length ()

Возвращает длину массива.

открытый набор void (int i, int newValue)

Устанавливает элемент в позиции i в указанное значение.

public String toString ()

Возвращает строковое представление текущих значений массива.

public boolean weakCompareAndSet (int i, int Ожидается, int обновление)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

пример

Следующая программа TestThread показывает использование переменной AtomicIntegerArray в среде, основанной на потоках.

Live Demo

import java.util.concurrent.atomic.AtomicIntegerArray;

public class TestThread {
   private static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);

   public static void main(final String[] arguments) throws InterruptedException {
      
      for (int i = 0; i<atomicIntegerArray.length(); i++) {
         atomicIntegerArray.set(i, 1);
      }

      Thread t1 = new Thread(new Increment());
      Thread t2 = new Thread(new Compare());
      t1.start();
      t2.start();

      t1.join();
      t2.join();

      System.out.println("Values: ");

      for (int i = 0; i<atomicIntegerArray.length(); i++) {
         System.out.print(atomicIntegerArray.get(i) + " ");
      }
   }

   static class Increment implements Runnable {

      public void run() {

         for(int i = 0; i<atomicIntegerArray.length(); i++) {
            int add = atomicIntegerArray.incrementAndGet(i);
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ add);
         }
      }
   }

   static class Compare implements Runnable {

      public void run() {

         for(int i = 0; i<atomicIntegerArray.length(); i++) {
            boolean swapped = atomicIntegerArray.compareAndSet(i, 2, 3);
            
            if(swapped) {
               System.out.println("Thread " + Thread.currentThread().getId()
                  + ", index " +i + ", value: 3");
            }
         }
      }
   }
}

Это даст следующий результат.

Выход

Thread 10, index 0, value: 2
Thread 10, index 1, value: 2
Thread 10, index 2, value: 2
Thread 11, index 0, value: 3
Thread 10, index 3, value: 2
Thread 11, index 1, value: 3
Thread 11, index 2, value: 3
Thread 10, index 4, value: 2
Thread 11, index 3, value: 3
Thread 10, index 5, value: 2
Thread 10, index 6, value: 2
Thread 11, index 4, value: 3
Thread 10, index 7, value: 2
Thread 11, index 5, value: 3
Thread 10, index 8, value: 2
Thread 11, index 6, value: 3
Thread 10, index 9, value: 2
Thread 11, index 7, value: 3
Thread 11, index 8, value: 3
Thread 11, index 9, value: 3
Values:
3 3 3 3 3 3 3 3 3 3

Параллелизм Java — класс AtomicLongArray

Класс java.util.concurrent.atomic.AtomicLongArray предоставляет операции с базовым длинным массивом, которые могут быть прочитаны и записаны атомарно, а также содержит расширенные атомарные операции. AtomicLongArray поддерживает атомарные операции с базовой переменной длинного массива. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Методы AtomicLongArray

Ниже приведен список важных методов, доступных в классе AtomicLongArray.

Sr.No. Метод и описание
1

public long addAndGet (int i, long delta)

Атомно добавляет данное значение к элементу по индексу i.

2

public boolean compareAndSet (int i, long ожидают, long update)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

3

общедоступный long декремент AndGet (int i)

Атомно уменьшает на единицу элемент с индексом i.

4

публично долго добираться (int i)

Получает текущее значение в позиции i.

5

public long getAndAdd (int i, long delta)

Атомно добавляет данное значение к элементу по индексу i.

6

public long getAndDecrement (int i)

Атомно уменьшает на единицу элемент с индексом i.

7

public long getAndIncrement (int i)

Атомно увеличивает на единицу элемент с индексом i.

8

public long getAndSet (int i, long newValue)

Атомно устанавливает элемент в позиции i на заданное значение и возвращает старое значение.

9

public long incrementAndGet (int i)

Атомно увеличивает на единицу элемент с индексом i.

10

public void lazySet (int i, long newValue)

В конце концов устанавливает элемент в позиции i на заданное значение.

11

public int length ()

Возвращает длину массива.

12

открытый набор void (int i, long newValue)

Устанавливает элемент в позиции i в указанное значение.

13

public String toString ()

Возвращает строковое представление текущих значений массива.

14

public boolean weakCompareAndSet (int i, long ожидают, long update)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

public long addAndGet (int i, long delta)

Атомно добавляет данное значение к элементу по индексу i.

public boolean compareAndSet (int i, long ожидают, long update)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

общедоступный long декремент AndGet (int i)

Атомно уменьшает на единицу элемент с индексом i.

публично долго добираться (int i)

Получает текущее значение в позиции i.

public long getAndAdd (int i, long delta)

Атомно добавляет данное значение к элементу по индексу i.

public long getAndDecrement (int i)

Атомно уменьшает на единицу элемент с индексом i.

public long getAndIncrement (int i)

Атомно увеличивает на единицу элемент с индексом i.

public long getAndSet (int i, long newValue)

Атомно устанавливает элемент в позиции i на заданное значение и возвращает старое значение.

public long incrementAndGet (int i)

Атомно увеличивает на единицу элемент с индексом i.

public void lazySet (int i, long newValue)

В конце концов устанавливает элемент в позиции i на заданное значение.

public int length ()

Возвращает длину массива.

открытый набор void (int i, long newValue)

Устанавливает элемент в позиции i в указанное значение.

public String toString ()

Возвращает строковое представление текущих значений массива.

public boolean weakCompareAndSet (int i, long ожидают, long update)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

пример

Следующая программа TestThread показывает использование переменной AtomicIntegerArray в среде, основанной на потоках.

Live Demo

import java.util.concurrent.atomic.AtomicLongArray;

public class TestThread {
   private static AtomicLongArray atomicLongArray = new AtomicLongArray(10);

   public static void main(final String[] arguments) throws InterruptedException {

      for (int i = 0; i<atomicLongArray.length(); i++) {
         atomicLongArray.set(i, 1);
      }

      Thread t1 = new Thread(new Increment());
      Thread t2 = new Thread(new Compare());
      t1.start();
      t2.start();

      t1.join();
      t2.join();

      System.out.println("Values: ");
      
      for (int i = 0; i<atomicLongArray.length(); i++) {
         System.out.print(atomicLongArray.get(i) + " ");
      }
   }  

   static class Increment implements Runnable {

      public void run() {

         for(int i = 0; i<atomicLongArray.length(); i++) {
            long add = atomicLongArray.incrementAndGet(i);
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ add);
         }
      }
   }

   static class Compare implements Runnable {

      public void run() {

         for(int i = 0; i<atomicLongArray.length(); i++) {
            boolean swapped = atomicLongArray.compareAndSet(i, 2, 3);
            
            if(swapped) {
               System.out.println("Thread " + Thread.currentThread().getId()
                  + ", index " +i + ", value: 3");
            }
         }
      }
   }
}

Это даст следующий результат.

Выход

Thread 9, index 0, value: 2
Thread 10, index 0, value: 3
Thread 9, index 1, value: 2
Thread 9, index 2, value: 2
Thread 9, index 3, value: 2
Thread 9, index 4, value: 2
Thread 10, index 1, value: 3
Thread 9, index 5, value: 2
Thread 10, index 2, value: 3
Thread 9, index 6, value: 2
Thread 10, index 3, value: 3
Thread 9, index 7, value: 2
Thread 10, index 4, value: 3
Thread 9, index 8, value: 2
Thread 9, index 9, value: 2
Thread 10, index 5, value: 3
Thread 10, index 6, value: 3
Thread 10, index 7, value: 3
Thread 10, index 8, value: 3
Thread 10, index 9, value: 3
Values: 
3 3 3 3 3 3 3 3 3 3

Класс AtomicReferenceArray

Класс java.util.concurrent.atomic.AtomicReferenceArray предоставляет операции с базовым ссылочным массивом, которые могут быть прочитаны и записаны атомарно, а также содержит расширенные атомарные операции. AtomicReferenceArray поддерживает атомарные операции с базовой переменной массива ссылок. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. У атомарного метода compareAndSet также есть эти особенности согласованности памяти.

Методы AtomicReferenceArray

Ниже приведен список важных методов, доступных в классе AtomicReferenceArray.

Sr.No. Метод и описание
1

public boolean compareAndSet (int i, E ожидают, E обновляют)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

2

публичный E get (int i)

Получает текущее значение в позиции i.

3

public E getAndSet (int i, E newValue)

Атомно устанавливает элемент в позиции i на заданное значение и возвращает старое значение.

4

public void lazySet (int i, E newValue)

В конце концов устанавливает элемент в позиции i на заданное значение.

5

public int length ()

Возвращает длину массива.

6

открытый набор void (int i, E newValue)

Устанавливает элемент в позиции i в указанное значение.

7

public String toString ()

Возвращает строковое представление текущих значений массива.

8

public boolean weakCompareAndSet (int i, E ожидают, E обновляют)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

public boolean compareAndSet (int i, E ожидают, E обновляют)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

публичный E get (int i)

Получает текущее значение в позиции i.

public E getAndSet (int i, E newValue)

Атомно устанавливает элемент в позиции i на заданное значение и возвращает старое значение.

public void lazySet (int i, E newValue)

В конце концов устанавливает элемент в позиции i на заданное значение.

public int length ()

Возвращает длину массива.

открытый набор void (int i, E newValue)

Устанавливает элемент в позиции i в указанное значение.

public String toString ()

Возвращает строковое представление текущих значений массива.

public boolean weakCompareAndSet (int i, E ожидают, E обновляют)

Атомно устанавливает элемент в позиции i на заданное обновленное значение, если текущее значение == ожидаемое значение.

пример

Следующая программа TestThread показывает использование переменной AtomicReferenceArray в среде, основанной на потоках.

Live Demo

import java.util.concurrent.atomic.AtomicReferenceArray;

public class TestThread {
   private static String[] source = new String[10];
   private static AtomicReferenceArray<String> atomicReferenceArray 
      = new AtomicReferenceArray<String>(source);

   public static void main(final String[] arguments) throws InterruptedException {

      for (int i = 0; i<atomicReferenceArray.length(); i++) {
         atomicReferenceArray.set(i, "item-2");
      }

      Thread t1 = new Thread(new Increment());
      Thread t2 = new Thread(new Compare());
      t1.start();
      t2.start();

      t1.join();
      t2.join();		
   }  

   static class Increment implements Runnable {
      
      public void run() {
         
         for(int i = 0; i<atomicReferenceArray.length(); i++) {
            String add = atomicReferenceArray.getAndSet(i,"item-"+ (i+1));
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ add);
         }
      }
   }

   static class Compare implements Runnable {
      
      public void run() {
         
         for(int i = 0; i<atomicReferenceArray.length(); i++) {
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ atomicReferenceArray.get(i));
            boolean swapped = atomicReferenceArray.compareAndSet(i, "item-2", "updated-item-2");
            System.out.println("Item swapped: " + swapped);
            
            if(swapped) {
               System.out.println("Thread " + Thread.currentThread().getId() 
                  + ", index " +i + ", updated-item-2");
            }
         }
      }
   }
}

Это даст следующий результат.

Выход

Thread 9, index 0, value: item-2
Thread 10, index 0, value: item-1
Item swapped: false
Thread 10, index 1, value: item-2
Item swapped: true
Thread 9, index 1, value: updated-item-2
Thread 10, index 1, updated-item-2
Thread 10, index 2, value: item-3
Item swapped: false
Thread 10, index 3, value: item-2
Item swapped: true
Thread 10, index 3, updated-item-2
Thread 10, index 4, value: item-2
Item swapped: true
Thread 10, index 4, updated-item-2
Thread 10, index 5, value: item-2
Item swapped: true
Thread 10, index 5, updated-item-2
Thread 10, index 6, value: item-2
Thread 9, index 2, value: item-2
Item swapped: true
Thread 9, index 3, value: updated-item-2
Thread 10, index 6, updated-item-2
Thread 10, index 7, value: item-2
Thread 9, index 4, value: updated-item-2
Item swapped: true
Thread 9, index 5, value: updated-item-2
Thread 10, index 7, updated-item-2
Thread 9, index 6, value: updated-item-2
Thread 10, index 8, value: item-2
Thread 9, index 7, value: updated-item-2
Item swapped: true
Thread 9, index 8, value: updated-item-2
Thread 10, index 8, updated-item-2
Thread 9, index 9, value: item-2
Thread 10, index 9, value: item-10
Item swapped: false

Java Concurrency — интерфейс исполнителя

Интерфейс java.util.concurrent.Executor — это простой интерфейс для поддержки запуска новых задач.

Методы ExecutorService

Sr.No. Метод и описание
1

void execute (команда Runnable)

Выполняет данную команду в будущем.

void execute (команда Runnable)

Выполняет данную команду в будущем.

пример

Следующая программа TestThread показывает использование интерфейса Executor в среде, основанной на потоках.

Live Demo

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      Executor executor = Executors.newCachedThreadPool();
      executor.execute(new Task());
      ThreadPoolExecutor pool = (ThreadPoolExecutor)executor;
      pool.shutdown();
   }  

   static class Task implements Runnable {
      
      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task!");
            TimeUnit.SECONDS.sleep(duration);
            System.out.println("Task Completed");
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

Running Task!
Task Completed

ExecutorService Interface

Интерфейс java.util.concurrent.ExecutorService является подынтерфейсом интерфейса Executor и добавляет функции для управления жизненным циклом как отдельных задач, так и самого исполнителя.

Методы ExecutorService

Sr.No. Метод и описание
1

логическое awaitTermination (длительное время ожидания, единица времени)

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

2

<T> Список <Future <T >> invokeAll (Коллекция <? Extends Callable <T >> tasks)

Выполняет заданные задачи, возвращая список Фьючерсов с их статусом и результатами, когда все выполнено.

3

<T> Список <Future <T >> invokeAll (Коллекция <? Extends Callable <T >> задач, длительный тайм-аут, блок TimeUnit)

Выполняет заданные задачи, возвращая список Фьючерсов с их статусом и результатами, когда все завершено или истекло время ожидания, в зависимости от того, что произойдет раньше.

4

<T> T invokeAny (Коллекция <? Расширяет Callable <T >> задач)

Выполняет заданные задачи, возвращая результат одного успешно выполненного задания (т. Е. Без исключения), если оно есть.

5

<T> T invokeAny (Коллекция <? Расширяет Callable <T >> задач, длительное время ожидания, блок TimeUnit)

Выполняет заданные задачи, возвращая результат одного успешно выполненного задания (т. Е. Без исключения), если оно выполнено до истечения заданного времени ожидания.

6

логическое isShutdown ()

Возвращает true, если этот исполнитель был закрыт.

7

логическое значение isTermination ()

Возвращает true, если все задачи были выполнены после завершения работы.

8

отключение пустоты ()

Инициирует упорядоченное завершение, при котором выполняются ранее отправленные задачи, но новые задачи не принимаются.

9

List <Runnable> shutdownNow ()

Пытается остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения.

10

<T> Future <T> submit (Callable <T> задача)

Передает задачу, возвращающую значение, для выполнения и возвращает Future, представляющий ожидающие результаты задачи.

11

Future <?> Submit (Выполняемая задача)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

12

<T> Future <T> submit (Выполненная задача, T результат)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

логическое awaitTermination (длительное время ожидания, единица времени)

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

<T> Список <Future <T >> invokeAll (Коллекция <? Extends Callable <T >> tasks)

Выполняет заданные задачи, возвращая список Фьючерсов с их статусом и результатами, когда все выполнено.

<T> Список <Future <T >> invokeAll (Коллекция <? Extends Callable <T >> задач, длительный тайм-аут, блок TimeUnit)

Выполняет заданные задачи, возвращая список Фьючерсов с их статусом и результатами, когда все завершено или истекло время ожидания, в зависимости от того, что произойдет раньше.

<T> T invokeAny (Коллекция <? Расширяет Callable <T >> задач)

Выполняет заданные задачи, возвращая результат одного успешно выполненного задания (т. Е. Без исключения), если оно есть.

<T> T invokeAny (Коллекция <? Расширяет Callable <T >> задач, длительное время ожидания, блок TimeUnit)

логическое isShutdown ()

Возвращает true, если этот исполнитель был закрыт.

логическое значение isTermination ()

Возвращает true, если все задачи были выполнены после завершения работы.

отключение пустоты ()

Инициирует упорядоченное завершение, при котором выполняются ранее отправленные задачи, но новые задачи не принимаются.

List <Runnable> shutdownNow ()

Пытается остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения.

<T> Future <T> submit (Callable <T> задача)

Передает задачу, возвращающую значение, для выполнения и возвращает Future, представляющий ожидающие результаты задачи.

Future <?> Submit (Выполняемая задача)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

<T> Future <T> submit (Выполненная задача, T результат)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

пример

Следующая программа TestThread показывает использование интерфейса ExecutorService в поточной среде.

Live Demo

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newSingleThreadExecutor();

      try {
         executor.submit(new Task());
         System.out.println("Shutdown executor");
         executor.shutdown();
         executor.awaitTermination(5, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
         System.err.println("tasks interrupted");
      } finally {

         if (!executor.isTerminated()) {
            System.err.println("cancel non-finished tasks");
         }
         executor.shutdownNow();
         System.out.println("shutdown finished");
      }
   }

   static class Task implements Runnable {
      
      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 20);
            System.out.println("Running Task!");
            TimeUnit.SECONDS.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }	   
}

Это даст следующий результат.

Выход

Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:302)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
	at TestThread$Task.run(TestThread.java:39)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)

ScheduledExecutorService Interface

Интерфейс java.util.concurrent.ScheduledExecutorService является подынтерфейсом интерфейса ExecutorService и поддерживает будущее и / или периодическое выполнение задач.

ScheduledExecutorService Методы

Sr.No. Метод и описание
1

Расписание <V> ScheduledFuture <V> (вызываемое <V>, длительная задержка, единица времени)

Создает и выполняет ScheduledFuture, которое становится активным после заданной задержки.

2

ScheduledFuture <?> Schedule (команда Runnable, длительная задержка, единица времени)

Создает и выполняет одноразовое действие, которое становится активным после заданной задержки.

3

ScheduledFuture <?> ScheduleAtFixedRate (команда Runnable, длинный initialDelay, длительный период, единица времени)

Создает и выполняет периодическое действие, которое становится активным сначала после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay + period, затем initialDelay + 2 * period и так далее.

4

ScheduledFuture <?> ScheduleWithFixedDelay (команда Runnable, long initialDelay, длинная задержка, единица времени)

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

Расписание <V> ScheduledFuture <V> (вызываемое <V>, длительная задержка, единица времени)

Создает и выполняет ScheduledFuture, которое становится активным после заданной задержки.

ScheduledFuture <?> Schedule (команда Runnable, длительная задержка, единица времени)

Создает и выполняет одноразовое действие, которое становится активным после заданной задержки.

ScheduledFuture <?> ScheduleAtFixedRate (команда Runnable, длинный initialDelay, длительный период, единица времени)

Создает и выполняет периодическое действие, которое становится активным сначала после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay + period, затем initialDelay + 2 * period и так далее.

ScheduledFuture <?> ScheduleWithFixedDelay (команда Runnable, long initialDelay, длинная задержка, единица времени)

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

пример

Следующая программа TestThread показывает использование интерфейса ScheduledExecutorService в поточной среде.

Live Demo

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler = 
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();			
         }
      }, 10, TimeUnit.SECONDS);
   }

   static class BeepTask implements Runnable {
      
      public void run() {
         System.out.println("beep");      
      }
   }
}

Это даст следующий результат.

Выход

beep
beep
beep
beep

Метод newFixedThreadPool

Фиксированный пул потоков можно получить, вызвав статический метод newFixedThreadPool () класса Executors.

Синтаксис

ExecutorService fixedPool = Executors.newFixedThreadPool(2);

где

  • Максимум 2 потока будут активны для обработки задач.

  • Если передано более двух потоков, они удерживаются в очереди, пока потоки не станут доступными.

  • Новый поток создается, чтобы занять его место, если поток завершается из-за сбоя во время выполнения, и завершение выполнения для исполнителя еще не вызвано.

  • Любой поток существует до тех пор, пока пул не будет закрыт.

Максимум 2 потока будут активны для обработки задач.

Если передано более двух потоков, они удерживаются в очереди, пока потоки не станут доступными.

Новый поток создается, чтобы занять его место, если поток завершается из-за сбоя во время выполнения, и завершение выполнения для исполнителя еще не вызвано.

Любой поток существует до тех пор, пока пул не будет закрыт.

пример

Следующая программа TestThread показывает использование метода newFixedThreadPool в среде, основанной на потоках.

Live Demo

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {
	
   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newFixedThreadPool(2);

      // Cast the object to its class type
      ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + pool.getCorePoolSize());
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.shutdown();
   }  

   static class Task implements Runnable {

      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
               TimeUnit.SECONDS.sleep(duration);
            
            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

Largest executions: 0
Maximum allowed threads: 2
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 2
Largest executions: 2
Maximum allowed threads: 2
Current threads in pool: 2
Currently executing threads: 1
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1

Метод newCachedThreadPool

Пул кэшированных потоков можно получить, вызвав статический метод newCachedThreadPool () класса Executors.

Синтаксис

ExecutorService executor = Executors.newCachedThreadPool();

где

  • Метод newCachedThreadPool создает исполнителя с расширяемым пулом потоков.

  • Такой исполнитель подходит для приложений, которые запускают множество краткосрочных задач.

Метод newCachedThreadPool создает исполнителя с расширяемым пулом потоков.

Такой исполнитель подходит для приложений, которые запускают множество краткосрочных задач.

пример

Следующая программа TestThread показывает использование метода newCachedThreadPool в среде, основанной на потоках.

Live Demo

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {
	
   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newCachedThreadPool();

      // Cast the object to its class type
      ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + pool.getCorePoolSize());
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.shutdown();
   }  

   static class Task implements Runnable {

      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
               TimeUnit.SECONDS.sleep(duration);
            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 2
Maximum allowed threads: 2147483647
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1

Метод newScheduledThreadPool

Запланированный пул потоков можно получить путем вызова статического метода newScheduledThreadPool () класса Executors.

Синтаксис

ExecutorService executor = Executors.newScheduledThreadPool(1);

пример

Следующая программа TestThread показывает использование метода newScheduledThreadPool в среде, основанной на потоках.

Live Demo

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler = 
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();			
         }
      }, 10, TimeUnit.SECONDS);
   }  

   static class BeepTask implements Runnable {

      public void run() {
         System.out.println("beep");      
      }
   }
}

Это даст следующий результат.

Выход

beep
beep
beep
beep

Метод newSingleThreadExecutor

Один пул потоков можно получить, вызвав статический метод newSingleThreadExecutor () класса Executors.

Синтаксис

ExecutorService executor = Executors.newSingleThreadExecutor();

Где метод newSingleThreadExecutor создает исполнителя, который выполняет одну задачу за раз.

пример

Следующая программа TestThread показывает использование метода newSingleThreadExecutor в среде, основанной на потоках.

Live Demo

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newSingleThreadExecutor();

      try {
         executor.submit(new Task());
         System.out.println("Shutdown executor");
         executor.shutdown();
         executor.awaitTermination(5, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
         System.err.println("tasks interrupted");
      } finally {

         if (!executor.isTerminated()) {
            System.err.println("cancel non-finished tasks");
         }
         executor.shutdownNow();
         System.out.println("shutdown finished");
      }
   }

   static class Task implements Runnable {
      
      public void run() {

         try {
            Long duration = (long) (Math.random() * 20);
            System.out.println("Running Task!");
            TimeUnit.SECONDS.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:302)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
	at TestThread$Task.run(TestThread.java:39)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)

Класс ThreadPoolExecutor

java.util.concurrent.ThreadPoolExecutor — это ExecutorService для выполнения каждой переданной задачи с использованием одного из, возможно, нескольких объединенных потоков, обычно настраиваемых с использованием фабричных методов Executors. Он также предоставляет различные служебные методы для проверки статистики текущих потоков и управления ими.

Методы ThreadPoolExecutor

Sr.No. Метод и описание
1

защищенная пустота afterExecute (Runnable r, Throwable t)

Метод вызывается после завершения выполнения данного Runnable.

2

void allowCoreThreadTimeOut (логическое значение)

Устанавливает политику, определяющую, могут ли основные потоки блокировать время ожидания и завершаться, если в течение времени поддержки не поступают никакие задачи, и при необходимости заменяются при поступлении новых задач.

3

boolean allowCoreThreadTimeOut ()

Возвращает значение true, если этот пул позволяет основным потокам выполнять тайм-аут и завершать работу, если в течение времени keepAlive задачи не поступают, и при необходимости заменяться при поступлении новых задач.

4

логическое awaitTermination (длительное время ожидания, единица времени)

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

5

защищенный void beforeExecute (поток t, Runnable r)

Метод вызывается до выполнения данного Runnable в указанном потоке.

6

void execute (команда Runnable)

Выполняет задание когда-нибудь в будущем.

7

финал защищенный void ()

Вызывает завершение работы, когда на этого исполнителя больше нет ссылок, и у него нет потоков.

8

int getActiveCount ()

Возвращает приблизительное количество потоков, которые активно выполняют задачи.

9

long getCompletedTaskCount ()

Возвращает приблизительное общее количество задач, которые завершили выполнение.

10

int getCorePoolSize ()

Возвращает количество ядер.

11

long getKeepAliveTime (единица времени)

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

12

int getLargestPoolSize ()

Возвращает наибольшее количество потоков, которые когда-либо были одновременно в пуле.

13

int getMaximumPoolSize ()

Возвращает максимально допустимое количество потоков.

14

int getPoolSize ()

Возвращает текущее количество потоков в пуле.

15

BlockingQueue getQueue ()

Возвращает очередь задач, использованную этим исполнителем.

15

RejectedExecutionHandler getRejectedExecutionHandler ()

Возвращает текущий обработчик для неисполнимых задач.

16

long getTaskCount ()

Возвращает приблизительное общее количество задач, которые когда-либо были запланированы для выполнения.

17

ThreadFactory getThreadFactory ()

Возвращает фабрику потоков, использованную для создания новых потоков.

18

логическое isShutdown ()

Возвращает true, если этот исполнитель был закрыт.

19

логическое значение isTermination ()

Возвращает true, если все задачи были выполнены после завершения работы.

20

логическое isTerminating ()

Возвращает true, если этот исполнитель находится в процессе завершения после shutdown () или shutdownNow (), но не завершился полностью.

21

int prestartAllCoreThreads ()

Запускает все основные потоки, заставляя их бездействовать в ожидании работы.

22

логический prestartCoreThread ()

Запускает основной поток, заставляя его бездействовать в ожидании работы.

23

очистка от пустот ()

Пытается удалить из рабочей очереди все будущие задачи, которые были отменены.

24

логическое удаление (Runnable задача)

Удаляет эту задачу из внутренней очереди исполнителя, если она присутствует, в результате чего она не запускается, если она еще не запущена.

25

void setCorePoolSize (int corePoolSize)

Устанавливает количество ядер.

26

void setKeepAliveTime (долгое время, единица времени)

Устанавливает время, в течение которого потоки могут оставаться бездействующими до завершения

27

void setMaximumPoolSize (int MaximumPoolSize)

Устанавливает максимально допустимое количество потоков.

28

void setRejectedExecutionHandler (обработчик RejectedExecutionHandler)

Устанавливает новый обработчик для неисполнимых задач.

29

void setThreadFactory (ThreadFactory threadFactory)

Устанавливает фабрику потоков, используемую для создания новых потоков.

30

отключение пустоты ()

Инициирует упорядоченное завершение, при котором выполняются ранее отправленные задачи, но новые задачи не принимаются.

31

List <Runnable> shutdownNow ()

Пытается остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения.

32

защищенная пустота прекращена ()

Метод вызывается после завершения Исполнителя.

33

Строка toString ()

Возвращает строку, идентифицирующую этот пул, а также его состояние, включая индикаторы состояния выполнения и приблизительное число рабочих и задач.

защищенная пустота afterExecute (Runnable r, Throwable t)

Метод вызывается после завершения выполнения данного Runnable.

void allowCoreThreadTimeOut (логическое значение)

Устанавливает политику, определяющую, могут ли основные потоки блокировать время ожидания и завершаться, если в течение времени поддержки не поступают никакие задачи, и при необходимости заменяются при поступлении новых задач.

boolean allowCoreThreadTimeOut ()

Возвращает значение true, если этот пул позволяет основным потокам выполнять тайм-аут и завершать работу, если в течение времени keepAlive задачи не поступают, и при необходимости заменяться при поступлении новых задач.

логическое awaitTermination (длительное время ожидания, единица времени)

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

защищенный void beforeExecute (поток t, Runnable r)

Метод вызывается до выполнения данного Runnable в указанном потоке.

void execute (команда Runnable)

Выполняет задание когда-нибудь в будущем.

финал защищенный void ()

Вызывает завершение работы, когда на этого исполнителя больше нет ссылок, и у него нет потоков.

int getActiveCount ()

Возвращает приблизительное количество потоков, которые активно выполняют задачи.

long getCompletedTaskCount ()

Возвращает приблизительное общее количество задач, которые завершили выполнение.

int getCorePoolSize ()

Возвращает количество ядер.

long getKeepAliveTime (единица времени)

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

int getLargestPoolSize ()

Возвращает наибольшее количество потоков, которые когда-либо были одновременно в пуле.

int getMaximumPoolSize ()

Возвращает максимально допустимое количество потоков.

int getPoolSize ()

Возвращает текущее количество потоков в пуле.

BlockingQueue getQueue ()

Возвращает очередь задач, использованную этим исполнителем.

RejectedExecutionHandler getRejectedExecutionHandler ()

Возвращает текущий обработчик для неисполнимых задач.

long getTaskCount ()

Возвращает приблизительное общее количество задач, которые когда-либо были запланированы для выполнения.

ThreadFactory getThreadFactory ()

Возвращает фабрику потоков, использованную для создания новых потоков.

логическое isShutdown ()

Возвращает true, если этот исполнитель был закрыт.

логическое значение isTermination ()

Возвращает true, если все задачи были выполнены после завершения работы.

логическое isTerminating ()

Возвращает true, если этот исполнитель находится в процессе завершения после shutdown () или shutdownNow (), но не завершился полностью.

int prestartAllCoreThreads ()

Запускает все основные потоки, заставляя их бездействовать в ожидании работы.

логический prestartCoreThread ()

Запускает основной поток, заставляя его бездействовать в ожидании работы.

очистка от пустот ()

Пытается удалить из рабочей очереди все будущие задачи, которые были отменены.

логическое удаление (Runnable задача)

Удаляет эту задачу из внутренней очереди исполнителя, если она присутствует, в результате чего она не запускается, если она еще не запущена.

void setCorePoolSize (int corePoolSize)

Устанавливает количество ядер.

void setKeepAliveTime (долгое время, единица времени)

Устанавливает время, в течение которого потоки могут оставаться бездействующими до завершения

void setMaximumPoolSize (int MaximumPoolSize)

Устанавливает максимально допустимое количество потоков.

void setRejectedExecutionHandler (обработчик RejectedExecutionHandler)

Устанавливает новый обработчик для неисполнимых задач.

void setThreadFactory (ThreadFactory threadFactory)

Устанавливает фабрику потоков, используемую для создания новых потоков.

отключение пустоты ()

Инициирует упорядоченное завершение, при котором выполняются ранее отправленные задачи, но новые задачи не принимаются.

List <Runnable> shutdownNow ()

Пытается остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения.

защищенная пустота прекращена ()

Метод вызывается после завершения Исполнителя.

Строка toString ()

Возвращает строку, идентифицирующую этот пул, а также его состояние, включая индикаторы состояния выполнения и приблизительное число рабочих и задач.

пример

Следующая программа TestThread показывает использование интерфейса ThreadPoolExecutor в среде на основе потоков.

Live Demo

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {
	
   public static void main(final String[] arguments) throws InterruptedException {
      ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + executor.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + executor.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + executor.getPoolSize());
      System.out.println("Currently executing threads: "
         + executor.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + executor.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + executor.getCorePoolSize());
      System.out.println("Largest executions: "
         + executor.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + executor.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + executor.getPoolSize());
      System.out.println("Currently executing threads: "
         + executor.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + executor.getTaskCount());

      executor.shutdown();
   }  

   static class Task implements Runnable {

      public void run() {

         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(duration);
            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 2
Maximum allowed threads: 2147483647
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-2
Running Task! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-2

ScheduledThreadPoolExecutor Класс

java.util.concurrent.ScheduledThreadPoolExecutor является подклассом ThreadPoolExecutor и может дополнительно запланировать выполнение команд после заданной задержки или периодическое выполнение.

Методы ScheduledThreadPoolExecutor

Sr.No. Метод и описание
1

защищенный <V> RunnableScheduledFuture <V> decorateTask (Callable <V> callable, RunnableScheduledFuture <V> задача)

Изменяет или заменяет задачу, используемую для выполнения вызова.

2

защищенный <V> RunnableScheduledFuture <V> decorateTask (Runnable runnable, задача RunnableScheduledFuture <V>)

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

3

void execute (команда Runnable)

Выполняет команду с нулевой задержкой.

4

boolean getContinueExistingPeriodicTasksAfterShutdownPolicy ()

Получает политику о том, продолжать ли выполнение существующих периодических задач, даже если этот исполнитель был выключен.

5

boolean getExecuteExistingDelayedTasksAfterShutdownPolicy ()

Получает политику о том, выполнять ли существующие отложенные задачи, даже если этот исполнитель был выключен.

6

BlockingQueue <Runnable> getQueue ()

Возвращает очередь задач, использованную этим исполнителем.

7

логическое значение getRemoveOnCancelPolicy ()

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

8

Расписание <V> ScheduledFuture <V> (вызываемое <V>, длительная задержка, единица времени)

Создает и выполняет ScheduledFuture, которое становится активным после заданной задержки.

9

ScheduledFuture <?> Schedule (команда Runnable, длительная задержка, единица времени)

Создает и выполняет одноразовое действие, которое становится активным после заданной задержки.

10

ScheduledFuture <?> ScheduleAtFixedRate (команда Runnable, длинный initialDelay, длительный период, единица времени)

Создает и выполняет периодическое действие, которое становится активным сначала после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay + period, затем initialDelay + 2 * period и так далее.

11

ScheduledFuture <?> ScheduleWithFixedDelay (команда Runnable, long initialDelay, длинная задержка, единица времени)

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

12

void setContinueExistingPeriodicTasksAfterShutdownPolicy (логическое значение)

Устанавливает политику относительно продолжения выполнения существующих периодических задач, даже если этот исполнитель был выключен.

13

void setExecuteExistingDelayedTasksAfterShutdownPolicy (логическое значение)

Устанавливает политику для выполнения существующих отложенных задач, даже когда этот исполнитель был выключен.

14

void setRemoveOnCancelPolicy (логическое значение)

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

15

отключение пустоты ()

Инициирует упорядоченное завершение, при котором выполняются ранее отправленные задачи, но новые задачи не принимаются.

16

List <Runnable> shutdownNow ()

Пытается остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения.

17

<T> Future <T> submit (Callable <T> задача)

Передает задачу, возвращающую значение, для выполнения и возвращает Future, представляющий ожидающие результаты задачи.

18

Future <?> Submit (Выполняемая задача)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

19

<T> Future <T> submit (Выполненная задача, T результат)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

защищенный <V> RunnableScheduledFuture <V> decorateTask (Callable <V> callable, RunnableScheduledFuture <V> задача)

Изменяет или заменяет задачу, используемую для выполнения вызова.

защищенный <V> RunnableScheduledFuture <V> decorateTask (Runnable runnable, задача RunnableScheduledFuture <V>)

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

void execute (команда Runnable)

Выполняет команду с нулевой задержкой.

boolean getContinueExistingPeriodicTasksAfterShutdownPolicy ()

Получает политику о том, продолжать ли выполнение существующих периодических задач, даже если этот исполнитель был выключен.

boolean getExecuteExistingDelayedTasksAfterShutdownPolicy ()

Получает политику о том, выполнять ли существующие отложенные задачи, даже если этот исполнитель был выключен.

BlockingQueue <Runnable> getQueue ()

Возвращает очередь задач, использованную этим исполнителем.

логическое значение getRemoveOnCancelPolicy ()

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

Расписание <V> ScheduledFuture <V> (вызываемое <V>, длительная задержка, единица времени)

Создает и выполняет ScheduledFuture, которое становится активным после заданной задержки.

ScheduledFuture <?> Schedule (команда Runnable, длительная задержка, единица времени)

Создает и выполняет одноразовое действие, которое становится активным после заданной задержки.

ScheduledFuture <?> ScheduleAtFixedRate (команда Runnable, длинный initialDelay, длительный период, единица времени)

Создает и выполняет периодическое действие, которое становится активным сначала после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay + period, затем initialDelay + 2 * period и так далее.

ScheduledFuture <?> ScheduleWithFixedDelay (команда Runnable, long initialDelay, длинная задержка, единица времени)

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

void setContinueExistingPeriodicTasksAfterShutdownPolicy (логическое значение)

Устанавливает политику относительно продолжения выполнения существующих периодических задач, даже если этот исполнитель был выключен.

void setExecuteExistingDelayedTasksAfterShutdownPolicy (логическое значение)

Устанавливает политику для выполнения существующих отложенных задач, даже когда этот исполнитель был выключен.

void setRemoveOnCancelPolicy (логическое значение)

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

отключение пустоты ()

Инициирует упорядоченное завершение, при котором выполняются ранее отправленные задачи, но новые задачи не принимаются.

List <Runnable> shutdownNow ()

Пытается остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения.

<T> Future <T> submit (Callable <T> задача)

Передает задачу, возвращающую значение, для выполнения и возвращает Future, представляющий ожидающие результаты задачи.

Future <?> Submit (Выполняемая задача)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

<T> Future <T> submit (Выполненная задача, T результат)

Передает задачу Runnable для выполнения и возвращает Future, представляющий эту задачу.

пример

Следующая программа TestThread показывает использование интерфейса ScheduledThreadPoolExecutor в среде, основанной на потоках.

Live Demo

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledThreadPoolExecutor scheduler = 
         (ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler = 
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();			
         }
      }, 10, TimeUnit.SECONDS);
   }  

   static class BeepTask implements Runnable {
      
      public void run() {
         System.out.println("beep");      
      }
   }
}

Это даст следующий результат.

Выход

beep
beep
beep
beep

Параллелизм Java — Фьючерсы и Callables

Объект java.util.concurrent.Callable может возвращать вычисленный результат, выполненный потоком, в отличие от запускаемого интерфейса, который может только запустить поток. Объект Callable возвращает объект Future, который предоставляет методы для отслеживания хода выполнения задачи потоком. Будущий объект может быть использован для проверки состояния вызываемого объекта и последующего извлечения результата из вызываемого объекта после завершения потока. Это также обеспечивает функциональность тайм-аута.

Синтаксис

//submit the callable using ThreadExecutor
//and get the result as a Future object
Future<Long> result10 = executor.submit(new FactorialService(10));
 
//get the result using get method of the Future object
//get method waits till the thread execution and then return the result of the execution.
Long factorial10 = result10.get();

пример

Следующая программа TestThread показывает использование Futures и Callables в поточной среде.

Live Demo

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException,
      ExecutionException {

      ExecutorService executor = Executors.newSingleThreadExecutor();

      System.out.println("Factorial Service called for 10!");
      Future<Long> result10 = executor.submit(new FactorialService(10));

      System.out.println("Factorial Service called for 20!");
      Future<Long> result20 = executor.submit(new FactorialService(20));

      Long factorial10 = result10.get();
      System.out.println("10! = " + factorial10);

      Long factorial20 = result20.get();
      System.out.println("20! = " + factorial20);

      executor.shutdown();
   }  

   static class FactorialService implements Callable<Long> {
      private int number;

      public FactorialService(int number) {
         this.number = number;
      }

      @Override
      public Long call() throws Exception {
         return factorial();
      }

      private Long factorial() throws InterruptedException {
         long result = 1; 
         
         while (number != 0) { 
            result = number * result; 
            number--; 
            Thread.sleep(100); 
         }
         return result;	
      }
   }
}

Это даст следующий результат.

Выход

Factorial Service called for 10!
Factorial Service called for 20!
10! = 3628800
20! = 2432902008176640000

Java Concurrency — платформа Fork-Join

Фреймворк fork-join позволяет разбить определенную задачу на нескольких рабочих, а затем дождаться результата, чтобы объединить их. Он в значительной степени использует возможности многопроцессорной машины. Ниже приведены основные понятия и объекты, используемые в инфраструктуре fork-join.

вилка

Форк — это процесс, в котором задача разделяется на более мелкие и независимые подзадачи, которые могут выполняться одновременно.

Синтаксис

Sum left  = new Sum(array, low, mid);
left.fork();

Здесь Sum является подклассом RecursiveTask, а left.fork () разбивает задачу на подзадачи.

Присоединиться

Присоединение — это процесс, в котором задача объединяет все результаты подзадач после завершения выполнения подзадач, в противном случае она продолжает ждать.

Синтаксис

left.join();

Здесь слева находится объект класса Sum.

ForkJoinPool

это специальный пул потоков, предназначенный для работы с разделением задач по типу ветвления и объединения.

Синтаксис

ForkJoinPool forkJoinPool = new ForkJoinPool(4);

Здесь новый ForkJoinPool с уровнем параллелизма 4 процессоров.

RecursiveAction

RecursiveAction представляет задачу, которая не возвращает никакого значения.

Синтаксис

class Writer extends RecursiveAction {
   @Override
   protected void compute() { }
}

RecursiveTask

RecursiveTask представляет задачу, которая возвращает значение.

Синтаксис

class Sum extends RecursiveTask<Long> {
   @Override
   protected Long compute() { return null; }
}

пример

Следующая программа TestThread показывает использование инфраструктуры Fork-Join в среде, основанной на потоках.

Live Demo

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException, 
      ExecutionException {
      
      int nThreads = Runtime.getRuntime().availableProcessors();
      System.out.println(nThreads);
      
      int[] numbers = new int[1000]; 

      for(int i = 0; i < numbers.length; i++) {
         numbers[i] = i;
      }

      ForkJoinPool forkJoinPool = new ForkJoinPool(nThreads);
      Long result = forkJoinPool.invoke(new Sum(numbers,0,numbers.length));
      System.out.println(result);
   }  

   static class Sum extends RecursiveTask<Long> {
      int low;
      int high;
      int[] array;

      Sum(int[] array, int low, int high) {
         this.array = array;
         this.low   = low;
         this.high  = high;
      }

      protected Long compute() {
         
         if(high - low <= 10) {
            long sum = 0;
            
            for(int i = low; i < high; ++i) 
               sum += array[i];
               return sum;
         } else {	    	
            int mid = low + (high - low) / 2;
            Sum left  = new Sum(array, low, mid);
            Sum right = new Sum(array, mid, high);
            left.fork();
            long rightResult = right.compute();
            long leftResult  = left.join();
            return leftResult + rightResult;
         }
      }
   }
}

Это даст следующий результат.

Выход

32
499500

Java Concurrency — интерфейс BlockingQueue

Интерфейс java.util.concurrent.BlockingQueue является подынтерфейсом интерфейса очереди и дополнительно поддерживает такие операции, как ожидание того, что очередь станет непустой перед извлечением элемента, и ожидание появления пространства в очереди перед сохранением элемента. ,

Методы блокировки

Sr.No. Метод и описание
1

логическое сложение (E e)

Вставляет указанный элемент в эту очередь, если это можно сделать немедленно, не нарушая ограничения емкости, возвращая true при успешном завершении и выбрасывая исключение IllegalStateException, если в настоящее время нет свободного места.

2

логическое значение содержит (объект o)

Возвращает true, если эта очередь содержит указанный элемент.

3

int driTo (Коллекция <? super E> c)

Удаляет все доступные элементы из этой очереди и добавляет их в заданную коллекцию.

4

int driTo (Коллекция <? super E> c, int maxElements)

Удаляет не более заданного количества доступных элементов из этой очереди и добавляет их в заданную коллекцию.

5

булево предложение (E e)

Вставляет указанный элемент в эту очередь, если это можно сделать немедленно, не нарушая ограничения по емкости, возвращая значение true в случае успеха и значение false, если в настоящее время нет свободного места.

6

логическое предложение (E e, длительное время ожидания, единица времени)

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

7

E опрос (длительное время ожидания, единица времени)

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

8

пустота (E e)

Вставляет указанный элемент в эту очередь, ожидая, если необходимо, чтобы освободилось место.

9

int оставшийсяCapacity ()

Возвращает количество дополнительных элементов, которые эта очередь может в идеале (при отсутствии ограничений памяти или ресурсов) принять без блокировки, или Integer.MAX_VALUE, если нет внутреннего ограничения.

10

логическое удаление (объект o)

Удаляет один экземпляр указанного элемента из этой очереди, если он присутствует.

11

E взять ()

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

логическое сложение (E e)

Вставляет указанный элемент в эту очередь, если это можно сделать немедленно, не нарушая ограничения емкости, возвращая true при успешном завершении и выбрасывая исключение IllegalStateException, если в настоящее время нет свободного места.

логическое значение содержит (объект o)

Возвращает true, если эта очередь содержит указанный элемент.

int driTo (Коллекция <? super E> c)

Удаляет все доступные элементы из этой очереди и добавляет их в заданную коллекцию.

int driTo (Коллекция <? super E> c, int maxElements)

Удаляет не более заданного количества доступных элементов из этой очереди и добавляет их в заданную коллекцию.

булево предложение (E e)

Вставляет указанный элемент в эту очередь, если это можно сделать немедленно, не нарушая ограничения по емкости, возвращая значение true в случае успеха и значение false, если в настоящее время нет свободного места.

логическое предложение (E e, длительное время ожидания, единица времени)

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

E опрос (длительное время ожидания, единица времени)

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

пустота (E e)

Вставляет указанный элемент в эту очередь, ожидая, если необходимо, чтобы освободилось место.

int оставшийсяCapacity ()

Возвращает количество дополнительных элементов, которые эта очередь может в идеале (при отсутствии ограничений памяти или ресурсов) принять без блокировки, или Integer.MAX_VALUE, если нет внутреннего ограничения.

логическое удаление (объект o)

Удаляет один экземпляр указанного элемента из этой очереди, если он присутствует.

E взять ()

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

пример

Следующая программа TestThread показывает использование интерфейса BlockingQueue в поточной среде.

Live Demo

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10);

      Producer producer = new Producer(queue);
      Consumer consumer = new Consumer(queue);

      new Thread(producer).start();
      new Thread(consumer).start();

      Thread.sleep(4000);
   }  


   static class Producer implements Runnable {
      private BlockingQueue<Integer> queue;

      public Producer(BlockingQueue queue) {
         this.queue = queue;
      }

      @Override
      public void run() {
         Random random = new Random();

         try {
            int result = random.nextInt(100);
            Thread.sleep(1000);
            queue.put(result);
            System.out.println("Added: " + result);
            
            result = random.nextInt(100);
            Thread.sleep(1000);
            queue.put(result);
            System.out.println("Added: " + result);
            
            result = random.nextInt(100);
            Thread.sleep(1000);
            queue.put(result);
            System.out.println("Added: " + result);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }	   
   }

   static class Consumer implements Runnable {
      private BlockingQueue<Integer> queue;

      public Consumer(BlockingQueue queue) {
         this.queue = queue;
      }
      
      @Override
      public void run() {
         
         try {
            System.out.println("Removed: " + queue.take());
            System.out.println("Removed: " + queue.take());
            System.out.println("Removed: " + queue.take());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

Это даст следующий результат.

Выход

Added: 52
Removed: 52
Added: 70
Removed: 70
Added: 27
Removed: 27

Java Concurrency — интерфейс ConcurrentMap

Интерфейс java.util.concurrent.ConcurrentMap является подынтерфейсом интерфейса Map, поддерживает элементарные операции над базовой переменной map. У него есть методы get и set, которые работают как чтение и запись по переменным переменным. То есть набор имеет отношение «происходит до» с любым последующим получением той же переменной. Этот интерфейс обеспечивает безопасность потока и гарантии атомарности.

Методы ConcurrentMap

Sr.No. Метод и описание
1

V вычисление по умолчанию (клавиша K, BiFunction <? super K?? super V? расширяет V> remappingFunction)

Пытается вычислить сопоставление для указанного ключа и его текущего сопоставленного значения (или ноль, если текущего сопоставления нет).

2

по умолчанию V computeIfAbsent (клавиша K, функция <? super K, extends V> mappingFunction)

Если указанный ключ еще не связан со значением (или сопоставлен со значением NULL), он пытается вычислить его значение с использованием заданной функции сопоставления и вводит его в эту карту, если не имеет значение NULL.

3

по умолчанию V computeIfPresent (клавиша K, BiFunction <? super K,? super V, расширяет V> remappingFunction)

Если значение для указанного ключа присутствует и не равно нулю, выполняется попытка вычислить новое сопоставление с учетом ключа и его текущего сопоставленного значения.

4

по умолчанию void forEach (действие BiConsumer <? super K,? super V>)

Выполняет данное действие для каждой записи в этой карте, пока все записи не будут обработаны или действие не вызовет исключение.

5

V getOrDefault по умолчанию (ключ объекта, V defaultValue)

Возвращает значение, которому сопоставлен указанный ключ, или defaultValue, если эта карта не содержит сопоставления для ключа.

6

V-слияние по умолчанию (ключ K, значение V, BiFunction <? super V,? super V, extends V> remappingFunction)

Если указанный ключ еще не связан со значением или связан с нулем, связывает его с заданным ненулевым значением.

7

V putIfAbsent (ключ K, значение V)

Если указанный ключ еще не связан со значением, свяжите его с данным значением.

8

логическое удаление (ключ объекта, значение объекта)

Удаляет запись для ключа только в том случае, если в данный момент сопоставлено заданному значению.

9

Заменить V (ключ K, значение V)

Заменяет запись для ключа только в том случае, если в данный момент сопоставлено с некоторым значением.

10

логическая замена (клавиша K, V oldValue, V newValue)

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

11

по умолчанию void replaceAll (BiFunction <? super K,? super V, extends V> function)

Заменяет значение каждой записи на результат вызова данной функции для этой записи, пока все записи не будут обработаны или функция не выдаст исключение.

V вычисление по умолчанию (клавиша K, BiFunction <? super K?? super V? расширяет V> remappingFunction)

Пытается вычислить сопоставление для указанного ключа и его текущего сопоставленного значения (или ноль, если текущего сопоставления нет).

по умолчанию V computeIfAbsent (клавиша K, функция <? super K, extends V> mappingFunction)

Если указанный ключ еще не связан со значением (или сопоставлен со значением NULL), он пытается вычислить его значение с использованием заданной функции сопоставления и вводит его в эту карту, если не имеет значение NULL.

по умолчанию V computeIfPresent (клавиша K, BiFunction <? super K,? super V, расширяет V> remappingFunction)

Если значение для указанного ключа присутствует и не равно нулю, выполняется попытка вычислить новое сопоставление с учетом ключа и его текущего сопоставленного значения.

по умолчанию void forEach (действие BiConsumer <? super K,? super V>)

Выполняет данное действие для каждой записи в этой карте, пока все записи не будут обработаны или действие не вызовет исключение.

V getOrDefault по умолчанию (ключ объекта, V defaultValue)

Возвращает значение, которому сопоставлен указанный ключ, или defaultValue, если эта карта не содержит сопоставления для ключа.

V-слияние по умолчанию (ключ K, значение V, BiFunction <? super V,? super V, extends V> remappingFunction)

Если указанный ключ еще не связан со значением или связан с нулем, связывает его с заданным ненулевым значением.

V putIfAbsent (ключ K, значение V)

Если указанный ключ еще не связан со значением, свяжите его с данным значением.

логическое удаление (ключ объекта, значение объекта)

Удаляет запись для ключа только в том случае, если в данный момент сопоставлено заданному значению.

Заменить V (ключ K, значение V)

Заменяет запись для ключа только в том случае, если в данный момент сопоставлено с некоторым значением.

логическая замена (клавиша K, V oldValue, V newValue)

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

по умолчанию void replaceAll (BiFunction <? super K,? super V, extends V> function)

Заменяет значение каждой записи на результат вызова данной функции для этой записи, пока все записи не будут обработаны или функция не выдаст исключение.

пример

Следующая программа TestThread показывает использование ConcurrentMap против HashMap.

Live Demo

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TestThread {

   public static void main(final String[] arguments) {
      Map<String,String> map = new ConcurrentHashMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial ConcurrentHashMap: " + map);
      Iterator<String> iterator = map.keySet().iterator();

      try { 
         
         while(iterator.hasNext()) {
            String key = iterator.next();
            
            if(key.equals("3")) {
               map.put("4", "Four");
            }
         }
      } catch(ConcurrentModificationException cme) {
         cme.printStackTrace();
      }
      System.out.println("ConcurrentHashMap after modification: " + map);

      map = new HashMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial HashMap: " + map);
      iterator = map.keySet().iterator();

      try {
         
         while(iterator.hasNext()) {
            String key = iterator.next();
            
            if(key.equals("3")) {
               map.put("4", "Four");
            }
         }
         System.out.println("HashMap after modification: " + map);
      } catch(ConcurrentModificationException cme) {
         cme.printStackTrace();
      }
   }  
}

Это даст следующий результат.

Выход

Initial ConcurrentHashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
ConcurrentHashMap after modification: {1 = One, 2 = Two, 3 = Three, 4 = Four, 5 = Five, 6 = Six}
Initial HashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(Unknown Source)
	at java.util.HashMap$KeyIterator.next(Unknown Source)
	at TestThread.main(TestThread.java:48)

Интерфейс ConcurrentNavigableMap

Интерфейс java.util.concurrent.ConcurrentNavigableMap является подынтерфейсом интерфейса ConcurrentMap и поддерживает операции NavigableMap, а также рекурсивно для его навигационных подкарт и приблизительных совпадений.

Методы ConcurrentMap

Sr.No. Метод и описание
1

NavigableSet <K> нисходящийKeySet ()

Возвращает представление NavigableSet в обратном порядке для ключей, содержащихся в этой карте.

2

ConcurrentNavigableMap <K, V> убывающая карта ()

Возвращает представление в обратном порядке отображений, содержащихся в этой карте.

3

ConcurrentNavigableMap <K, V> headMap (K toKey)

Возвращает представление части этой карты, чьи ключи строго меньше, чем toKey.

4

ConcurrentNavigableMap <K, V> headMap (K toKey, логическое значение включительно)

Возвращает представление части этой карты, ключи которой меньше (или равны, если inclusive истина) toKey.

5

NavigableSet <K> keySet ()

Возвращает представление NavigableSet ключей, содержащихся в этой карте.

6

NavigableSet <K> navigableKeySet ()

Возвращает представление NavigableSet ключей, содержащихся в этой карте.

7

SubMap ConcurrentNavigableMap <K, V> (K fromKey, логическое значение от Inclusive, K toKey, логическое значение toInclusive)

Возвращает представление части этой карты, ключи которой варьируются от fromKey до toKey.

8

SubMap ConcurrentNavigableMap <K, V> (K fromKey, K toKey)

Возвращает представление части этой карты, ключи которой варьируются от fromKey, включительно, до toKey, эксклюзив.

9

ConcurrentNavigableMap <K, V> tailMap (K fromKey)

Возвращает представление части этой карты, ключи которой больше или равны fromKey.

10

ConcurrentNavigableMap <K, V> tailMap (K fromKey, логическое значение включительно)

Возвращает представление части этой карты, ключи которой больше (или равны, если inclusive true) fromKey.

NavigableSet <K> нисходящийKeySet ()

Возвращает представление NavigableSet в обратном порядке для ключей, содержащихся в этой карте.

ConcurrentNavigableMap <K, V> убывающая карта ()

Возвращает представление в обратном порядке отображений, содержащихся в этой карте.

ConcurrentNavigableMap <K, V> headMap (K toKey)

Возвращает представление части этой карты, чьи ключи строго меньше, чем toKey.

ConcurrentNavigableMap <K, V> headMap (K toKey, логическое значение включительно)

Возвращает представление части этой карты, ключи которой меньше (или равны, если inclusive истина) toKey.

NavigableSet <K> keySet ()

Возвращает представление NavigableSet ключей, содержащихся в этой карте.

NavigableSet <K> navigableKeySet ()

Возвращает представление NavigableSet ключей, содержащихся в этой карте.

SubMap ConcurrentNavigableMap <K, V> (K fromKey, логическое значение от Inclusive, K toKey, логическое значение toInclusive)

Возвращает представление части этой карты, ключи которой варьируются от fromKey до toKey.

SubMap ConcurrentNavigableMap <K, V> (K fromKey, K toKey)

Возвращает представление части этой карты, ключи которой варьируются от fromKey, включительно, до toKey, эксклюзив.

ConcurrentNavigableMap <K, V> tailMap (K fromKey)

Возвращает представление части этой карты, ключи которой больше или равны fromKey.

ConcurrentNavigableMap <K, V> tailMap (K fromKey, логическое значение включительно)

Возвращает представление части этой карты, ключи которой больше (или равны, если inclusive true) fromKey.

пример

Следующая программа TestThread показывает использование ConcurrentNavigableMap.

Live Demo

import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

public class TestThread {

   public static void main(final String[] arguments) {
      ConcurrentNavigableMap<String,String> map =
         new ConcurrentSkipListMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial ConcurrentHashMap: "+map);
      System.out.println("HeadMap(\"2\") of ConcurrentHashMap: "+map.headMap("2"));
      System.out.println("TailMap(\"2\") of ConcurrentHashMap: "+map.tailMap("2"));
      System.out.println(
         "SubMap(\"2\", \"4\") of ConcurrentHashMap: "+map.subMap("2","4"));
   }  
}

Это даст следующий результат.