[Java] Multithread-Verarbeitung - Exklusive Steuerung

Achten Sie bei der Multithread-Verarbeitung auf die gemeinsame Nutzung von Daten

NG Beispiel

//NG Beispiel
public class SynchronizedNotUse {
//Daten, die von mehreren Threads gemeinsam genutzt werden
  private int value = 0;

//Führen Sie 100.000 Threads aus
  public static void main(String[] args) {
    final int TASK_NUM = 100000;
    var th = new Thread[TASK_NUM];
    var tb = new SynchronizedNotUse();
    //Thread-Erstellung und Ausführung
    for (var i = 0; i < TASK_NUM; i++) {
      th[i] = new Thread(() -> {
        tb.increment();
      });
      th[i].start();
    }
    //Warten Sie bis zum Ende des Threads
    for (var i = 0; i < TASK_NUM; i++) {
      try {
        th[i].join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    System.out.println(tb.value); //Jedes Mal anders
  }
  //Inkrementieren Sie das Wertefeld
  void increment() {
    this.value++;
  }
}

Exklusive Steuerung mit synchronisiertem Block

public class SynchronizedUse {
  private int value = 0;

  public static void main(String[] args) {
    final int TASK_NUM = 100000;
    var th = new Thread[TASK_NUM];
    var tb = new SynchronizedUse();
    for (var i = 0; i < TASK_NUM; i++) {
      th[i] = new Thread(() -> {
        tb.increment();
      });
      th[i].start();
    }
    for (var i = 0; i < TASK_NUM; i++) {
      try {
        th[i].join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    System.out.println(tb.value);
  }
   //Geben Sie das zu sperrende Objekt als aktuelle Instanz an
  void increment() {
    synchronized(this) {
      this.value++;
    }
  }
}

synchronisierter Modifikator

synchronized void increment() {
    this.value++;
}

Explizite Sperre

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

public class LockBasic {
  private int value = 0;
  private final Lock lock = new ReentrantLock();

  public static void main(String[] args) {
    final int TASK_NUM = 100000;
    var th = new Thread[TASK_NUM];
    var tb = new LockBasic();
    for (var i = 0; i < TASK_NUM; i++) {
      th[i] = new Thread(() -> {
        tb.increment();
      });
      th[i].start();
    }
    for (var i = 0; i < TASK_NUM; i++) {
      try {
        th[i].join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    System.out.println(tb.value);
  }


  void increment() {
    //Sperrenerfassung
    lock.lock();
    try {
      this.value++;
    } finally {
      //Freischalten
      lock.unlock();
    }
  }
}

** tryLock-Methode **

  if (lock.tryLock(10,TimeUnit.SECONDS)) {
    try {
    //Verarbeitung, die ausschließlich kontrolliert werden sollte
    } finally {
      lock.unlock();
    }
  }else{
  //Was tun, wenn Sie kein Schloss bekommen können?
}

Schlossfreie exklusive Kontrolle

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicBasic {
  private AtomicInteger value = new AtomicInteger();

  public static void main(String[] args) {
    final int TASK_NUM = 100000;
    var th = new Thread[TASK_NUM];
    var tb = new AtomicBasic();
    for (var i = 0; i < TASK_NUM; i++) {
      th[i] = new Thread(() -> {
        tb.increment();
      });
      th[i].start();
    }
    for (var i = 0; i < TASK_NUM; i++) {
      try {
        th[i].join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println(tb.value);
  }

  void increment() {
    value.getAndIncrement();
  }
}

Thread-Pool

public class ThreadPool implements Runnable {
  @Override
  public void run() {
    for (var i = 0; i < 30; i++){
      System.out.println(Thread.currentThread().getName() + ":" + i);
    }
  }
}
import java.util.concurrent.Executors;

public class ThreadPoolBasic {

  public static void main(String[] args) {
    //Generieren Sie einen Thread-Pool mit 10 Threads
    var es = Executors.newFixedThreadPool(10);
    //Aufruf und Ausführung mit der Methode execute
    es.execute(new ThreadPool());
    es.execute(new ThreadPool());
    es.execute(new ThreadPool());
    es.shutdown();
  }
}

Planen Sie die Ausführung

import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadSchedule {
  public static void main(String[] args) {
  //Vorbereitung des Fadenpools
    var sche = Executors.newScheduledThreadPool(2);
  //Planen Sie die Ausführungsregistrierung
    sche.scheduleAtFixedRate(() -> {
      System.out.println(LocalDateTime.now());
    }, 0, 5, TimeUnit.SECONDS);

    //Halten Sie den Hauptthread an, der auf die Ausführung des Zeitplans wartet
    try {
      Thread.sleep(10000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    //Fahren Sie den Thread-Pool herunter
    sche.shutdown();
  }
}

Empfangen Sie das Verarbeitungsergebnis des Threads

//Suchen Sie eine Zufallszahl in einem anderen Thread und halten Sie einige Millisekunden an
//Zeigen Sie den Wert im Haupt-Thread an
import java.util.Random;
import java.util.concurrent.Callable;

//Callable<Integer>Weisen Sie den Integer-Typ mit zu
public class ThreadCallable implements Callable<Integer> {
  @Override
  //Code, der in der Callable-Schnittstelle ausgeführt werden soll
  public Integer call() throws Exception {
    var rnd = new Random();
    var num = rnd.nextInt(1000);
    Thread.sleep(num);
    return num;
  }
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;

public class ThreadCallableBasic {

  public static void main(String[] args) {
  //Thread-Ausführung
    var exe = Executors.newSingleThreadExecutor();
    var r1 = exe.submit(new ThreadCallable());
    var r2 = exe.submit(new ThreadCallable());
    var r3 = exe.submit(new ThreadCallable());

  //Thread-Ergebnisanzeige
    //Der Rückgabewert der Submit-Methode ist Future<Integer>
    try {
      System.out.println("r1: " + r1.get());
      System.out.println("r2: " + r2.get());
      System.out.println("r3: " + r3.get());
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    exe.shutdown();
  }
}

Nachbearbeitung der Thread-Verarbeitung

//Suchen Sie eine Zufallszahl in einem anderen Thread und halten Sie einige Millisekunden an
//Zeigen Sie seinen Wert

import java.util.Random;
import java.util.concurrent.CompletableFuture;

public class FutureBasic {

  public static void main(String[] args) {
    //Ausführung der asynchronen Verarbeitung
    CompletableFuture.supplyAsync(() -> {
      var r = new Random();
      var num = r.nextInt(1000);
      heavy(num);
      return num;
    })
      //Verarbeitung nach Abschluss
      .thenAcceptAsync((result) -> {
        System.out.println(result);
      });
    System.out.println("...Nachbearbeitung...");
    heavy(7000);
  }
  //Die Dummy-Verarbeitung (schwer) unterbricht die Verarbeitung nur für die angegebene Zeit
  public static void heavy(int num) {
    try {
      Thread.sleep(num);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

Erfolg / Fehlerbehandlung sortieren

import java.util.Random;
import java.util.concurrent.CompletableFuture;

public class FutureComplete {

  public static void main(String[] args) {
    CompletableFuture.supplyAsync(() -> {
      var r = new Random();
      var num = r.nextInt(1000);
      heavy(num);
      return num;
    })
      .whenCompleteAsync((result, ex) -> {
        //Erfolg
        if (ex == null) {
          System.out.println(result);
        } else {
        //Fehler
          System.out.println(ex.getMessage());
        }
      });
    heavy(7000);
  }

  public static void heavy(int num) {
    try {
      Thread.sleep(num);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

Führen Sie mehrere asynchrone Prozesse in Reihe aus

import java.util.Random;
import java.util.concurrent.CompletableFuture;

public class FutureSeq {

  public static void main(String[] args) {
  //Prozess 1(Zufällige Generierung)
    CompletableFuture.supplyAsync(() -> {
      var r = new Random();
      var num = r.nextInt(5000);
      heavy(2000);
      System.out.printf("Prozess 1: %d\n", num);
      return num;
    })
  //Prozess 2(Zufällige Zeiten)
    .thenApplyAsync((data) -> {
      var result = data * 2;
      heavy(2000);
      System.out.printf("Prozess 2: %d\n", result);
      return result;
    })
  //Prozess 3(Zufälliges Doppel)
    .thenAcceptAsync((data) -> {
      var num = data * 2;
      heavy(2000);
      System.out.printf("Prozess 3: %d\n", num);
    });
    heavy(7000);
  }

  public static void heavy(int num) {
    try {
      Thread.sleep(num);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

Recommended Posts

[Java] Multithread-Verarbeitung - Exklusive Steuerung
[Java] Multithread-Verarbeitung
Java-Steuerungssyntax
Java-Steuerungssyntax
Java-Thread-Verarbeitung
Java-String-Verarbeitung
[Java] Stream-Verarbeitung
Java iterativer Prozess
[Java] Hinweis zur Steuerungssyntax
JAVA-Konstruktoraufrufverarbeitung
Java zufällig, verschiedene Verarbeitung
Java-Versionsverwaltung unter macOS
Java-Versionsverwaltung mit SDKMAN
Java-Versionsverwaltung mit jenv
[Java] Stream API - Stream-Beendigungsverarbeitung
[Java] Stream API - Stream Zwischenverarbeitung
[Java] Implementierungsmethode für die Timer-Verarbeitung
☾ Java / Repeat-Anweisung und Repeat-Steueranweisung
Gemessene Parallelverarbeitung mit Java
Grundlegendes zur Java-Parallelverarbeitung (Einführung)
[Java] Zusammenfassung der Steuerungssyntax
Zusammenfassung der Java-Fehlerverarbeitung
[ev3 × Java] Anzeige, Ton, LED-Steuerung
Datumsverarbeitung in Java (LocalDate: Initialisierung)
Delegieren Sie Java-Verarbeitung an JavaScript
[Java] Schleifenverarbeitung und Tabelle von neunundneunzig
Führen Sie node.js von Android Java aus (Verarbeitung)
[Verarbeitung × Java] Verwendung von Variablen
Hinweise zur Signalsteuerung in Java
Serververarbeitung mit Java (Einführung Teil.1)
Überraschend tiefe Java-Liste Inversion-Stream-Verarbeitung
Grundlegender Verarbeitungsablauf von Java Stream
Informationen zur Dateikopierverarbeitung in Java
Löschen von Dateien mit rekursiver Verarbeitung [Java]
[Verarbeitung × Java] Verwendung von Arrays
[Java] Memo zur Verarbeitungszeitmessmethode
[Java] Ausnahmetypen und grundlegende Verarbeitung
Dies und das der ausschließlichen Kontrolle
[ev3 × Java] Einzelmotorsteuerung