English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
1Was ist ein Problem der Parallelität.
Mehrere Prozesse oder Threads, die gleichzeitig (oder in gleicher Zeit) auf denselben Ressource zugreifen, verursachen Probleme der Parallelität.
Zwei Bediener der Bank, die gleichzeitig dasselbe Konto bearbeiten, ist ein typisches Beispiel. Zum Beispiel lesen die Bediener A und B gleichzeitig einen Saldo von1000 Yuan verringert, der A-Bedienung gleichzeitig das Konto um100 Yuan, der B-Bedienung gleichzeitig das Konto um50 Yuan, A erst einreichen, B später einreichen. Schließlich ist der tatsächliche Kontostand1000-50=950 Yuan, aber es sollte1000+100-50=1050. Dies ist ein typisches Problem der Parallelität. Wie kann es gelöst werden? Man kann ein Schloss verwenden.
2Verwendung von synchronized in Java
Verwendung1
public class Test{ public synchronized void print(){ ….; } }
Wenn ein Thread die Methode print() ausführt, wird dieses Objekt gesperrt. Andere Threads können keine synchronisierten Blöcke dieses Objekts ausführen.
Verwendung2
public class Test{ public void print(){ synchronized(this){ //sperrt dieses Objekt ...; } } }
gleiche Verwendung1, aber es kann die Essenz der Verwendung von synchronized besser zum Ausdruck bringen.
Verwendung3
public class Test{ private String a = "test"; public void print(){ synchronized(a){ //Das Objekt a sperren ...; } } public synchronized void t(){ ...; //Dieser Synchronisationscodeblock wird nicht durch print() gesperrt. } }
Das Ausführen von print() gibt dem Objekt a einen Lock, beachten Sie, dass es nicht den Lock des Objekts Test gibt, das bedeutet, dass die anderen synchronized-Methoden des Objekts Test nicht durch print() gesperrt werden. Nachdem der同步Codeblock abgeschlossen ist, wird der Lock von a freigegeben.
Um einen Codeblock eines Objekts zu sperren, ohne die anderen synchronized-Blöcke desselben Objekts zu beeinträchtigen, wird eine hochleistungsorientierte Schreibweise verwendet:
public class Test{ private byte[] lock = new byte[0]; public void print(){ synchronized(lock){ ...; } } public synchronized void t(){ ...; } }
Lock für statische Methoden
public class Test{ public synchronized static void execute(){ ...; } }
Der Effekt ist gleich
public class Test{ public static void execute(){ synchronized(TestThread.class){ ...; } } }
3 Die Locks in Java und das WC aufstellen.
Ein Lock ist eine Methode, um den Zugriff auf Ressourcen durch andere Prozesse oder Threads zu verhindern, d.h. gesperrte Ressourcen können nicht von anderen Anfragen aufgerufen werden. In Java wird der Schlüsselwort 'synchronized' verwendet, um ein Objekt zu sperren. Zum Beispiel:
public class MyStack { int idx = 0; char [] data = new char[6]; public synchronized void push(char c) { data[idx] = c; idx++; } public synchronized char pop() { idx--; return data[idx]; } public static void main(String args[]){ MyStack m = new MyStack(); /** Das Objekt m wird gesperrt. Genauer gesagt, alle synchronized-Blöcke des Objekts m werden gesperrt. Wenn eine andere Thread T versucht, auf m zuzugreifen, kann T die push- und pop-Methode. */ m.pop(); //Das Objekt m wird gesperrt. } }
Das Sperren und Entsperren von Locks in Java ist genau so, wie wenn mehrere Menschen auf einen gemeinsamen Toilettensitz warten. Wenn der Erste hineingegangen ist, sperrt er die Tür von innen, und die anderen müssen warten. Wenn der Erste fertig ist und herausgegangen ist, öffnet sich die Tür (entsperrt). Wenn der Zweite hineingehen darf, sperrt er ebenfalls die Tür von innen, und die anderen warten weiter.
Die Theorie der Toilette kann leicht verstanden werden: Wenn eine Person einen Toilettensitz betritt, wird dieser Sitz gesperrt, aber es führt nicht dazu, dass auch ein anderer Toilettensitz gesperrt wird, weil eine Person nicht gleichzeitig in zwei Toilettensitze sitzen kann. Für Java bedeutet das: Die Locks in Java sind für denselben Objekt bestimmt, nicht für die Klasse. Sehen wir uns ein Beispiel an:
=newMyStack();1=newMyStack(); =newMyStack();2MyStatckm .pop();1=newMystatck(); .pop();2=newMystatck();
.pop();1m2Objekt-Sperren nicht den Einfluss auf m3der Sperre, weil sie nicht der gleiche Toilettensitz sind. Das bedeutet, dass, wenn es1,t2,t3von den Threads t1Operation m3stehen, dann ist diese1warten, vorausgesetzt, ein anderer Thread könnte nur in m2von den Threads t8,t9während des Operationsvorgangs m2stehen, dann wird t8,t9wird nur in m2warten.2und t8hat nichts damit zu tun, selbst wenn m2aufgelegenen Sperren freigegeben werden, t1,t2,t3Es könnte auch in m1Stelle auf. Der Grund ist nicht anders, sie sind nicht der gleiche Toilettensitz.
Java kann nicht gleichzeitig zwei Sperren auf einen Codeblock anwenden, das ist anders als die Datenbank-Sperre, bei der gleichzeitig verschiedene Arten von Sperren auf ein Eintrag angewendet werden können.
4Wann wird die Sperre freigegeben?
Normalerweise wird nach Abschluss des Synchronisationsblocks (dem gesperrten Codeblock) die Sperre freigegeben, oder die Sperre kann mittels wait() halbwegs freigegeben werden. wait() ist wie halb im Badezimmer sitzen und plötzlich merken, dass die Kanalisation verstopft ist und man gezwungen ist, herauszugehen und sich an die Seite zu stellen, damit der Kanalreiniger (der bereitstehende Thread, der notify() ausführen soll) hinein kommt, den WC zu reinigen. Nachdem der Meister die Reinigung beendet hat, ruft er aus: 'Es ist fertig' (notify) und diejenigen, die herausgegangen sind, treten neu in die Reihe ein. Achtung, man muss warten, bis der Meister herauskommt, denn bis der Meister nicht herauskommt, kann niemand hineinkommen. Das bedeutet, nach notify() können andere Threads nicht sofort in den gesperrten Bereich eintreten, sondern müssen warten, bis der gesperrte Bereich, in dem das notify() befindet, beendet ist und die Sperre freigegeben wird, bevor andere Threads eintreten können.
Dies ist ein Beispiel für wait() und notify():
public synchronized char pop() { char c; while (buffer.size() == 0) { try { this.wait(); //Kommt aus der Toilettenspülung heraus } catch (InterruptedException e) { // ignoriere es… } } c = ((Character)buffer.remove(buffer.size());-1); charValue(); return c; } public synchronized void push(char c) { this.notify(); //Benachrichtige die Threads, die wait() aufrufen, neu zu排成队伍。注意:仅仅只是通知它们重新排队。 Character charObj = new Character(c); buffer.addElement(charObj); } //Durchführung abgeschlossen, Sperre freigeben. Die Warteschlange kann herein.
Er geht noch ein Stück tiefer.
Menschen, die aufgrund der wait()-Operation halbherzig herausgekommen sind, werden sich nicht neu in die Warteschlange einreihen, solange sie das notify-Signal nicht erhalten haben. Sie werden einfach an der Seite stehen und diese anstehen (darunter ist auch der Wasserinstallateur). Der Wasserinstallateur kann nicht vordrängen, er muss wie die anderen auf die Menschen, die auf die Toilette gehen, warten. Es bedeutet nicht, dass jemand halbheraus kommt und der Wasserinstallateur dann plötzlich auftaucht und sofort zur Reparatur geht, er muss mit den anderen, die in der Warteschlange stehen, fair umgehen, weil er auch ein normaler Thread ist. Wenn der Wasserinstallateur am Ende der Warteschlange steht, gehen diejenigen vor ihm hinein und finden, dass es verstopft ist, warten dann heraus, dann geht einer hinein, wartet, geht heraus, steht an der Seite, bis der Meister hinein geht und notify ausführt. In kurzer Zeit stehen viele Menschen an der Seite und warten auf notify.
Endlich geht der Meister hinein und notifyt, was dann?
1. Es gibt jemanden (Thread), der benachrichtigt wird.
2. Warum wurde er benachrichtigt und nicht einer der anderen waitenden? Es hängt vom JVM ab. Wir können es nicht vorher
bestimmen, welche benachrichtigt wird. Das bedeutet, dass höhere Prioritäten nicht unbedingt bevorzugt geweckt werden, und die Wartezeit
Lange Wartezeiten sind nicht unbedingt bevorzugt geweckt, alles ist unerwartet! (Natürlich, wenn du den JVM
Implementierung, kann vorhergesehen werden).
3. Er (der benachrichtigte Thread) muss neu in die Warteschlange eingereiht werden.
4. Wird er an der ersten Stelle der Warteschlange stehen? Die Antwort ist: nicht unbedingt. Wird er an der letzten Stelle stehen? Auch nicht unbedingt.
Wenn aber die Priorität des Threads höher eingestellt ist, dann ist die Wahrscheinlichkeit, dass er vorne steht, größer.
5. Wenn es an der Reihe ist, dass er neu in den Toilettensitz eintritt, wird er von dem Ort fortsetzen, an dem er zuletzt wait() aufgerufen hat, und wird nicht neu ausgeführt.
Schlecht gesagt, er wird weiter auf die Kakerlaken gehen, ohne neu zu ziehen.
6. Wenn der Meister notifyAll(). Dann werden alle, die halbherzig herausgekommen sind, neu in die Warteschlange eingereiht. Die Reihenfolge ist unbekannt.
Laut JavaDOC werden erweckte Threads nicht in der Lage sein, vor dem aktuellen Thread den Lock auf dieses Objekt abgibt (bis der aktuelle Thread den Lock auf dieses Objekt abgibt, können erweckte Threads nicht ausgeführt werden).
Das ist mit der Theorie der Toilettensitze offensichtlich.
5Verwendung von Lock
Mit dem Schlüsselwort synchronized kann auf Ressourcen gesperrt werden. Mit dem Lock-Schlüsselwort auch. Es ist JDK1.5neu hinzugefügt. Verwendungsbeispiel:
class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
(Anmerkung: Dies ist ein Beispiel in der JavaDoc, ein Beispiel für die Implementierung einer blockierenden Warteschlange. Eine blockierende Warteschlange ist eine Warteschlange, die blockiert, wenn sie voll oder leer ist und die Threads warten. In Java bietet ArrayBlockingQueue eine fertige blockierende Warteschlange, sodass man keine spezielle schreiben muss.)
Der Code zwischen dem lock.lock() und lock.unlock() eines Objekts wird gesperrt. Was ist besser daran im Vergleich zu synchronize? Kurz gesagt, es wird die Warteschlange der wartenden Threads klassifiziert. Mit der Theorie der Toilettensitze beschrieben, sind diejenigen, die auf halber Strecke aus dem WC herausgelaufen sind und darauf warten, dass der Grund unterschiedlich sein kann, sei es, weil der Toilettensitz verstopft ist, oder weil das Wasser fehlt. Wenn eine Benachrichtigung (notify) erfolgt, kann man rufen: Diejenigen, die darauf warten, dass der Toilettensitz verstopft ist, können neu in die Warteschlange einreihen (z.B. wurde das Problem mit dem verstopften Toilettensitz gelöst), oder rufen, diejenigen, die darauf warten, dass das Wasser fehlt, können neu in die Warteschlange einreihen (z.B. wurde das Problem mit dem fehlenden Wasser gelöst). Dies ermöglicht eine feinere Kontrolle. Im Gegensatz zu wait und notify in synchronize kann man nicht nur rufen: Diejenigen, die darauf gewartet haben, können neu in die Warteschlange einreihen! Wenn diejenigen, die in die Warteschlange einreihen, hineingehen und feststellen, dass nur das Problem mit dem verstopften Toilettensitz gelöst wurde, während das gewünschte Problem (kein Wasser im Toilettensitz) noch nicht gelöst wurde, müssen sie wieder darauf warten (wait) und umsonst umherlaufen, was Zeit und Ressourcen verschwendet.
Verhältnis zwischen Lock- und synchronized-Methoden:}
LockawaitsignalsignalAll
synchronizedwaitnotifynotifyAll
Achtung: Verwenden Sie nicht wait, notify, notifyAll im Block, der durch Lock-Methoden gesperrt ist
6Thread-zu-Thread-Kommunikation über Rohrleitung nutzen
Der Prinzip ist einfach. Zwei Threads, einer arbeitet mit PipedInputStream, der andere mit PipedOutputStream. Die Daten, die in den PipedOutputStream geschrieben werden, werden zunächst im Buffer zwischengespeichert. Wenn der Buffer voll ist, wartet dieser Thread. Der PipedInputStream liest die Daten aus dem Buffer. Wenn der Buffer keine Daten hat, wartet dieser Thread.
jdk1.5Die blockierende Queue kann die gleiche Funktion realisieren.
package io; import java.io.*; public class PipedStreamTest { public static void main(String[] args) { PipedOutputStream ops=new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(); try{ ops.connect(pis); //Verbindung der Rohrleitung implementieren new Producer(ops).run(); new Consumer(pis).run(); } catch(Exception e){ e.printStackTrace(); } } } //Produzent class Producer implements Runnable{ private PipedOutputStream ops; public Producer(PipedOutputStream ops) { this.ops = ops; } public void run() { try{ ops.write("hell,spell".getBytes()); ops.close(); } catch(Exception e) { e.printStackTrace(); } } } //Verbraucher class Consumer implements Runnable{ private PipedInputStream pis; public Consumer(PipedInputStream pis) { this.pis = pis; } public void run() { try{ byte[] bu = new byte[100]; int len = pis.read(bu); System.out.println(new String(bu, 0, len)); pis.close(); } catch(Exception e) { e.printStackTrace(); } } }
Beispiel2 Eine geringfügige Änderung des obigen Programms führt zu zwei Threads.
package io; import java.io.*; public class PipedStreamTest { public static void main(String[] args) { PipedOutputStream ops=new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(); try{ ops.connect(pis); //Verbindung der Rohrleitung implementieren Producer p = new Producer(ops); new Thread(p).start(); Consumer c = new Consumer(pis); new Thread(c).start(); } catch(Exception e){ e.printStackTrace(); } } } //Produzent class Producer implements Runnable{ private PipedOutputStream ops; public Producer(PipedOutputStream ops) { this.ops = ops; } public void run() { try{ for (;;){ ops.write("hell,spell".getBytes()); ops.close(); } } catch(Exception e) { e.printStackTrace(); } } } //Verbraucher class Consumer implements Runnable{ private PipedInputStream pis; public Consumer(PipedInputStream pis) { this.pis = pis; } public void run() { try{ for (;;){ byte[] bu = new byte[100]; int len = pis.read(bu); System.out.println(new String(bu, 0, len)); } pis.close(); } catch(Exception e) { e.printStackTrace(); } } }
Beispiel3Diese Beispiel ist näher an der Anwendung angepasst
import java.io.*; public class PipedIO { //Nach dem Ausführen des Programms wird der Inhalt der Datei sendFile in die Datei receiverFile kopiert public static void main(String args[]){ try{ //Erstellen Sie Objekte für die Schreib-Lese-Pipeline PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(); //Verwirklichen Sie die Verbindung pos.connect(pis); //Erstellen Sie zwei Threads und starten Sie sie. new Sender(pos, "c:\text2.txt).start(); new Receiver(pis, "c:\text3.txt).start(); } catch(IOException e){ System.out.println(„Pipe Error“+ e); } } } //Thread-Sendung class Sender extends Thread{ PipedOutputStream pos; File file; //Konstruktor Sender(PipedOutputStream pos, String fileName){ this.pos = pos; file = new File(fileName); } //Methode zur Thread-Ausführung public void run(){ try{ //Lesen Sie den Dateiinhalt FileInputStream fs = new FileInputStream(file); int data; while((data=fs.read())!=-1){ //Schreiben in den Anfang der Pipeline pos.write(data); } pos.close(); } catch(IOException e) { System.out.println(“Senderfehler” +e); } } } //Thread-Lesen class Receiver extends Thread{ PipedInputStream pis; File file; //Konstruktor Receiver(PipedInputStream pis, String fileName){ this.pis = pis; file = new File(fileName); } //Thread-Verlauf public void run(){ try { //Schreib-Stream-Objekt FileOutputStream fs = new FileOutputStream(file); int data; //Lesen vom Ende der Pipeline while((data=pis.read())!=-1){ //Schreiben in lokale Datei fs.write(data); } pis.close(); } catch(IOException e){ System.out.println("Empfängerfehler" +e); } } }
7BlockingQueue
BlockingQueues können das Pipeline-Stream-Verfahren ersetzen, um ein Einlaufformular zu realisieren/Drain-Pattern (Produzent/Konsument). JDK1.5Es werden einige fertige BlockingQueues bereitgestellt. Sehen wir uns nun den Code der ArrayBlockingQueue an:
Hier ist eine BlockingQueue
BlockingQueue blockingQ = new ArrayBlockingQueue 10;
Ein Thread nimmt aus der Warteschlange
for(;;){ Object o = blockingQ.take();//Wenn die Warteschlange leer ist, wird darauf gewartet (blockiert) }
Ein anderer Thread speichert in die Warteschlange
for(;;){ blockingQ.put(new Object());//Wenn die Warteschlange voll ist, wird darauf gewartet (blockiert) }
Es ist erkennbar, dass die Verwendung von BlockingQueues einfacher ist als bei Pfeifen.
8verwenden Executors, Executor, ExecutorService, ThreadPoolExecutor
Man kann Aufgaben mit Thread verwalten. Man kann auch JDK1.5Eine Reihe von Klassen, die das Verwalten von Aufgaben einfacher gestalten. Aus diesen Klassen können wir ein Aufgaben-orientiertes Denken verstehen. Diese Klassen sind:
Executor-Schnittstelle. Verwendungsweise:
Executor executor = anExecutor;//Erstellen Sie eine Instanz des Executors. executor.execute(new RunnableTask)}1());
Zweck: Der Benutzer muss sich nur um die Ausführung der Aufgaben kümmern und sich nicht darum kümmern, die Erstellung der Aufgaben und die Details der Ausführung zu überwachen, die die Drittanbieter interessieren. Das bedeutet, die Ausführung der Aufgabe und die Implementierung der Aufgabe zu entkoppeln.
Tatsächlich, JDK1.5Es gibt bereits eine hervorragende Implementierung dieser Schnittstelle. Das reicht aus.
Executors ist eine Art von Fabrikklasse oder Werkzeugklasse wie Collections, die verschiedene Schnittstelleninstanzen erzeugt.
Das Interface ExecutorService erbt von Executor.Executor und kümmert sich nur darum, Aufgaben in executor() auszuführen, und kümmert sich um den Rest nicht. Während ExecutorService jedoch etwas mehr Kontrollarbeit erledigt. Zum Beispiel:
class NetworkService { private final ServerSocket serverSocket; private final ExecutorService pool; public NetworkService(int port, int poolSize) throws IOException { serverSocket = new ServerSocket(port); pool = Executors.newFixedThreadPool(poolSize); } public void serve() { try { for (;;) { pool.execute(new Handler(serverSocket.accept())); } } catch (IOException ex) { pool.shutdown(); //Keine neuen Aufgaben mehr ausführen } } } class Handler implements Runnable { private final Socket socket; Handler(Socket socket) { this.socket = socket; } public void run() { // Lesen und Dienstleistung von Anfragen } }
Nach dem Ausführen von shutdown() durch ExecutorService (oder das Objekt pool im Code) kann er keine neuen Aufgaben mehr ausführen, aber alte Aufgaben werden weiterhin bis zum Abschluss ausgeführt, und die wartenden Aufgaben warten nicht mehr.
Der Kommunikationspartner des Aufgabenverfassers und Ausführers
public static void main(String args[])throws Exception { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable task = new Callable(){ public String call()throws Exception{ return "test"; } } ; Future f = executor.submit(task); String result = f.get(); //Wait (block) for the result to return System.out.println(result); executor.shutdown(); }
The Executor instance obtained by Executors.newSingleThreadExecutor() has the following characteristics:
Task execution in order. For example:
executor.submit(task1); executor.submit(task2);
must wait for task1After execution, task2can be executed.
task1and task2will be placed in a queue and processed by a working thread. That is: there are2threads (main thread, working thread that handles tasks).
For other classes, please refer to JavaDoc
9Concurrency process control
This example is from Wen's Java concurrency tutorial and may be modified. Salute to Wen.
CountDownLatch door bolt counter
Start threads and then wait for the threads to finish. This is the commonly used problem where the main thread waits for all child threads to finish before executing.
public static void main(String[] args)throws Exception { // TODO Auto-生成的方法存根 final int count=10; final CountDownLatch completeLatch = new CountDownLatch(count); //The number of door bolts defined is10 for (int i=0;i<count;i++){ Thread thread = new Thread("worker thread"+i){ public void run(){ //do xxxx completeLatch.countDown(); //减少一根门插销 } } ; thread.start(); } completeLatch.await(); //If the door bolt has not been fully reduced, wait. }
JDK1.4When this happens, a common approach is to set the state of the child thread and have the main thread loop to check. It is not very user-friendly or efficient.
Start many threads and wait for notification before starting.
public static void main(String[] args) throws Exception { // TODO Auto-生成的方法存根 final CountDownLatch startLatch = new CountDownLatch(1); //定义了一根门插销 for (int i = 0; i < 10; i++) { Thread thread = new Thread("worker thread" + i) { public void run() { try { startLatch.await(); //如果门插销还没减完则等待 } catch (InterruptedException e) { } // do xxxx } } ; thread.start(); } startLatch.countDown(); //减少一根门插销 }
CycliBarrier。所有线程都达到一个起跑线后才能开始继续运行。
public class CycliBarrierTest implements Runnable { private CyclicBarrier barrier; public CycliBarrierTest(CyclicBarrier barrier) { this.barrier = barrier; } public void run() { //do xxxx; try { this.barrier.await(); //线程运行至此会检查是否其他线程都到齐了,没到齐就继续等待。到齐了就执行barrier的run函数体里的内容 } catch (Exception e) { } } /** * @param args */ public static void main(String[] args) { //参数2代表两个线程都达到起跑线才开始一起继续往下执行 CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() { public void run() { //do xxxx; } } ); Thread t1 = new Thread(new CycliBarrierTest(barrier)); Thread t2 = new Thread(new CycliBarrierTest(barrier)); t1.start(); t2.start(); } }
这简化了传统的使用计数器+wait/使用notifyAll来实现该功能的方式。
10并发3定律
Amdahl定律。给定问题规模,可并行化部分占12%,那么即使把并行运用到极致,系统的性能最多也只能提高1/(1-0.12)=1.136倍。即:并行对提高系统性能有一个上限。
Gustafson-Gesetz. Das Gustafson-Gesetz sagt, dass das Amdahl-Gesetz nicht berücksichtigt hat, dass mit zunehmender Anzahl von CPU mehr Berechnungskapazität verfügbar ist. Die Essenz liegt darin, die Größe des Problems zu ändern, um die verbleibenden in der Amdahl-Gesetz zu ändern88% der serialen Verarbeitung in parallele Verarbeitung umgewandelt, so dass man die Leistungsgrenze überwinden kann. Es ist im Wesentlichen ein Raum gegen Zeit.
Sun-Ni-Gesetz. Das Ni-Gesetz ist eine weitere Erweiterung der ersten beiden Gesetze. Hauptgedanke ist, dass die Geschwindigkeit der Berechnung durch die Speicherkapazität und nicht durch die Geschwindigkeit der CPU begrenzt wird. Daher sollte der Speicherplatz und andere Berechnungsmittel充分利用 werden, um die Größe des Problems zu erhöhen, um bessere Ergebnisse zu erzielen/Genauere Lösungen.
11Von Konkurrenz zu Parallelität
Die Erkennung von Objekten durch Computer erfordert schnelle Berechnungen, bis hin zum Wärme- und Hitzeentwicklung im Chip, während die menschliche Erkennung von Objekten augenblicklich klar ist und nicht zu einer Unannehmlichkeit führt, dass eine einzelne Nervenzelle durch Hitze und Hitze verkocht (Übertreibung), da das Gehirn ein verteiltes paralleles Laufsystem ist, ähnlich wie Google mit einigen billigen Linux-Servern komplexe Berechnungen durchführen kann, die von einem einzigen CPU-Teraflop-Berechnungen erfordern, um in der Lage zu sein, sofortige Ergebnisse zu erzielen. Stell dir vor, wenn man im Bereich paralleler Verarbeitung etwas Neues geschaffen hätte, hätte es einen unermesslichen Einfluss auf die Entwicklung von Computern und die Zukunft haben. Natürlich sind die Herausforderungen ebenfalls vorhersehbar: Viele Probleme sind nicht leicht zu 'teilen'.
Zusammenfassung
Das ist das gesamte Inhaltsverzeichnis dieses Artikels über die Übersicht über Java-Konkurrenzprobleme. Hoffe, es hilft Ihnen. Freunde, die daran interessiert sind, können weiterhin andere relevante Themen dieser Website lesen. Willkommen zu Anmerkungen zu Unzulänglichkeiten. Vielen Dank für die Unterstützung der Freunde dieser Website!
Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem Urheberrechtlichem Eigentümer. Der Inhalt wurde von Internetbenutzern freiwillig beigesteuert und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht manuell bearbeitet. Sie übernimmt auch keine rechtlichen Verantwortlichkeiten. Wenn Sie verdächtige Urheberrechtsinhalte finden, freuen wir uns über eine E-Mail an: notice#oldtoolbag.com (Bitte ersetzen Sie # durch @, wenn Sie eine E-Mail senden, um zu melden, und stellen Sie relevante Beweise zur Verfügung. Sobald überprüft, wird die Website die涉嫌侵权的内 容立即删除。)