1 동시성 문제는 무엇입니까?
동일한 자원에 동시에 액세스하는 여러 프로세스 또는 스레드가 동시성 문제를 일으 킵니다.
일반적인 예는 두 은행 운영자가 동시에 동일한 계정을 운영한다는 것입니다. 예를 들어, 운영자 A와 B는 동시에 1,000 위안의 잔액을 가진 계정을 읽고, 운영자 A는 계정에 100 위안을 추가하고, 운영자 B는 계정에 대해 50 위안을 줄이고, A는 먼저 제출되고 B는 나중에 제출됩니다. 최종 실제 계정 잔액은 1000-50 = 950 위안이지만 1000+100-50 = 1050이어야합니다. 이것은 일반적인 동시성 문제입니다. 그것을 해결하는 방법? 자물쇠를 사용할 수 있습니다.
Java에서 동기화 된 2 가지
사용량 1
공개 클래스 테스트 {public synchronized void print () {….;}}스레드가 print () 메소드를 실행하면 객체가 잠겨 있습니다. 다른 스레드는 객체의 모든 동기화 된 블록을 실행할 수 없습니다.
사용 2
public class test {public void print () {synchronized (this) {//이 개체 잠금…;}}} 동일한 사용량 1이지만 동기화 된 사용의 본질을 더 잘 반영 할 수 있습니다.
사용법 3
공개 클래스 테스트 {private string a = "test"; public void print () {synchronized (a) {// 객체 잠금 ...;}} public synchronized void t () {… //이 동기화 된 코드 블록은 print ().}}로 인해 잠겨 있지 않습니다.print ()의 실행은 객체를 잠그게합니다. 테스트의 객체를 잠그지 않으므로 Test 객체의 다른 동기화 된 메소드는 print ()로 인해 잠겨 있지 않음을 의미합니다. 동기화 코드 블록이 실행되면 잠금 장치가 해제됩니다.
객체의 다른 동기화 된 블록의 고성능 쓰기에 영향을 미치지 않고 객체의 코드 블록을 잠그기 위해
공개 클래스 테스트 {private byte [] lock = new Byte [0]; public void print () {synchronized (lock) {…;}} public synchronized void t () {…;}}정적 메소드 잠금
공개 클래스 테스트 {public synchronized static void execute () {…;}}같은 효과
공개 클래스 테스트 {public static void execute () {synchronized (testthread.class) {…;}}}3 개의자가 잠금 장치와 대기열은 화장실로 이동합니다.
잠금 장치는 다른 프로세스 나 스레드가 리소스에 액세스하는 것을 방지하는 방법입니다. 즉, 잠긴 리소스는 다른 요청으로 액세스 할 수 없습니다. Java에서는 Sychronized 키워드가 객체를 잠그는 데 사용됩니다. 예를 들어:
공개 클래스 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 (indx]; 엄격히 말하면, 객체 m의 모든 동기화 된 블록이 잠겨 있습니다. M에 액세스하려는 다른 스레드 T가있는 경우 T는 M 객체의 푸시 및 POP 방법을 실행할 수 없습니다. */m.pop (); // 객체 m이 잠겨 있습니다. }}Java의 잠금 잠금 해제는 공중 화장실을 위해 대기하는 여러 사람과 정확히 동일합니다. 첫 번째 사람은 들어간 후 내부에서 문을 잠그 셨기 때문에 다른 사람은 줄을 서서 기다려야했습니다. 끝이 끝난 후 첫 번째 사람이 나오면 문이 열리십시오 (잠금 해제). 두 번째 사람이 들어가는 차례 였고, 그는 문을 다시 내부에서 잠그고 다른 사람들은 계속해서 줄을 서서 기다릴 것입니다.
화장실 이론을 사용하는 것은 쉽게 이해하기 쉽습니다. 사람이 화장실에 들어가면 화장실이 잠겨 있지만 한 사람이 동시에 두 화장실에서 쪼그리고 앉을 수 없기 때문에 다른 화장실이 잠겨 있지 않습니다. Java의 경우 : Java의 자물쇠는 클래스가 아닌 동일한 개체를 대상으로합니다. 다음 예를 참조하십시오.
mystatckm1 = newmystack (); mystatckm2 = newmystatck (); m1.pop (); m2.pop ();
M1 물체의 자물쇠는 M2의 자물쇠에 영향을 미치지 않습니다. 즉, 3 개의 스레드 T1, T2 및 T3이 M1을 작동하는 경우이 3 개의 스레드는 M1에서만 대기하고 대기 할 수 있습니다. 다른 2 스레드 T8, T9 작동 M2, T8, T9는 M2에서만 기다립니다. T2와 T8은 그것과 관련이 없습니다. M2의 잠금이 해제 되더라도 T1, T2 및 T3은 여전히 M1에서 대기해야 할 수 있습니다. 이유는 없습니다. 같은 변기 시트가 아닙니다.
Java는 동시에 코드 블록에 두 개의 잠금 장치를 추가 할 수 없습니다. 이것은 데이터베이스 잠금 메커니즘과 다릅니다. 데이터베이스는 동시에 레코드에 여러 다른 잠금 장치를 추가 할 수 있습니다.
4 자물쇠를 언제 출시해야합니까?
일반적으로 잠금은 동기화 코드 블록 (잠긴 코드 블록)이 실행 된 후에 해제되거나 잠금이 Wait () 메소드를 통해 중간 쯤에 해제 될 수 있습니다. Wait () 방법은 화장실에서 반쯤 쪼그리고 앉는 것과 같으며 갑자기 하수구가 막힌 것을 발견했습니다. 하수구 수리기 (알림을 실행할 준비가 된 실)가 화장실로 들어가서 청소할 수 있도록 옆으로 나와서 서서서야했습니다. 차단 해제 후 마스터는 "수리되었습니다." 방금 나온 동료들은 지금 그것을 듣고 난 후에 다시 줄을 섰습니다. 주의를 기울이십시오. 주인이 나올 때까지 기다려야합니다. 마스터가 나오지 않으면 아무도 들어갈 수 없습니다. 즉, 알림 후에는 다른 스레드가 차단 된 영역으로 들어가 즉시 이동할 수 있지만, 알림 코드가 실행되고 릴리스 된 차단 된 영역 후에 다른 스레드가 입력 할 수 있습니다.
다음은 대기 및 코드 알림 예입니다.
public synchronized char pop () {char c; while (buffer.size () == 0) {try {try {this.wait (); // 화장실} catch (InterpruptedException e) {// 무시…}} c = ((문자) buffer.remove (buffer.size ()-1). charValue (); return c;} public synchronized void push (char c) {this.notify (); // 해당 대기 () 스레드를 다시 대기열으로 알립니다. 참고 : 리큐어로 알려주십시오. 문자 charobj = new 문자 (c); buffer.addelement (charobj);} // 잠금을 실행하고 해제합니다. 그 대기열이 들어올 수 있습니다.더 깊이 가십시오.
Wait () 작전으로 인해 중간에 나온 동지들은 알림 신호를받을 때까지 대기를하지 않을 것입니다. 그는 옆에 사람들이 대기하는 사람들을 보았습니다 (워터 파이프 수리 마스터도 그들 중 하나입니다). 워터 파이프 수리 마스터는 라인으로 갈 수 없으며 화장실에가는 사람들처럼 대기해야합니다. 사람이 반쯤 쪼그리고 앉은 후에도 워터 파이프 수리 마스터가 갑자기 나타나서 즉시 수리 할 수있는 것은 아닙니다. 그는 원래 대기하는 사람들과 공정하게 경쟁하고 싶어합니다. 왜냐하면 그는 또한 평범한 실이기 때문입니다. 워터 파이프 수리 마스터가 뒤에 줄 지어 있다면, 앞에있는 사람은 막히고 기다렸다가 기다렸다가 옆으로 와서 기다렸다가 기다렸다가 옆으로 서서 마스터에게 가서 알림을 실행합니다. 이런 식으로, 잠시 후, 대기열 옆에 서서 알림을 기다리는 많은 사람들이있을 것입니다.
마지막으로, 마스터는 들어 와서 알렸다. 다음은 무엇입니까?
1. 대기자 (스레드)에 알림이 표시됩니다.
2. 왜 다른 대기자 대신에 통보를 받습니까? JVM에 따라 다릅니다. 우리는 선제적일 수 없습니다
어느 것을 알릴 것인지 결정하십시오. 다시 말해, 우선 순위가 높은 사람들은 먼저 깨어나지 않을 수 있습니다.
언제라도 먼저 깨어날 필요는 없습니다. 모든 것이 예측할 수 없습니다! (물론 JVM을 알고 있다면
구현하면 예측할 수 있습니다).
3. 그 (스레드 알림)는 다시 대기해야합니다.
4. 그는 라인에서 처음에있을 것인가? 대답은 : 확실하지 않습니다. 그가 마지막 사람이 될까요? 반드시 그런 것은 아닙니다.
그러나 스레드의 우선 순위가 상대적으로 높아지면 첫 순위가 먼저 순위가 높을 확률이 비교적 높습니다.
5. 화장실에 다시 들어가는 것이 그의 차례 일 때, 그는 마지막 Wait () 장소에서 계속 처형 될 것이며 다시 실행되지 않습니다.
역겨운 방식으로 그것을 넣으려면, 그는 다시는 울부 짖지 않고 다시 울부 짖을 것입니다.
6. 마스터 notifyall ()이라면 중간을 포기한 모든 사람들이 다시 줄을옵니다. 주문은 알려져 있지 않습니다.
Javadoc은 TheawakenedthreadswillnotbebletoproceedThurrentTherrentThreadTreLinquishTheLockonThisObject (현재 스레드가 잠금을 방출하기 전에 깨어 난 스레드를 실행할 수 없음)라고 말합니다.
이것은 변기 이론을 사용하여 설명하는 것이 분명합니다.
5Lock 사용
동기화 된 키워드를 사용하여 리소스를 잠그십시오. 잠금 키워드도 괜찮습니다. JDK1.5의 새로운 것입니다. 사용법은 다음과 같습니다.
class boundedBuffer {Final Lock Lock = New ReintrantLock (); 최종 조건 notefull = lock.newcondition (); 최종 조건 notempty = lock.newCondition (); 최종 객체 [] items = new Object [100]; int putptr, takeptr, count; public void put (객체 x)는 {while (while {workted genge); notfull.await (); 항목 [puttptr] = x; if (++ putptr == items.length) putptr = 0; ++ count; notempty.signal ();} 최종적으로 {lock.unlock ();}} public object take () throws interruptedException {lock.lock (); 항목 [takeptr]; if (++ takeptr == items.length) takeptr = 0;-count; notfull.signal (); return x;} 최종적으로 {lock.unlock ();}}}(참고 : 이것은 차단 대기열의 구현 예인 Javadoc의 예입니다. 소위 차단 큐는 큐가 가득 차 있거나 비어 있으면 스레드 차단 및 대기를 유발한다는 것을 의미합니다. Java의 배열 블록 큐는 기성품 블로킹 큐를 제공 할 필요가 없습니다.
객체의 lock.lock ()과 lek.unlock () 사이의 코드가 잠겨 있습니다. 동기화와 비교 하여이 방법에 대한 더 좋은 점은 무엇입니까? 요컨대, 대기 스레드를 분류합니다. 화장실 이론을 사용하여 설명하기 위해, 반쯤 쪼그리고 앉아 화장실에서 나와 대기하는 사람들은 다른 이유가있을 수 있습니다. 일부는 화장실이 막히고 일부는 화장실이 물이 없기 때문입니다. 알림을 받으면 소리를 지르면 화장실이 차단 될 때까지 기다리면 다시 줄을 서서 (예 : 화장실이 차단 된 문제가 해결 되었음) 화장실이 차단 될 때까지 기다리면 다시 줄을 서게됩니다 (예 : 화장실의 문제가 해결되었습니다). 이를 통해보다 자세한 제어가 가능합니다. 대기와 동기화 된 대기와 달리, 화장실이 막히거나 화장실이 물이 없든, 당신은 소리를 질 수 있습니다. 줄을 서서보고 보이면 화장실의 문제가 해결되었고, 해결하기를 간절히 바라는 문제 (화장실에는 물이 없음) 아직 해결되지 않았으므로 돌아가서 기다려야하고 헛되이 시간과 자원을 낭비해야합니다.
잠금 방법과 동기화 간의 해당 관계 :
LockaitignalSignalall
SynchronizedWaitNotifyNotifyall
참고 : 잠금에 의해 잠겨있는 블록의 대기, 알림, 알림, 알림을받지 마십시오.
6. 파이프 라인을 사용하여 스레드간에 통신하십시오
원칙은 간단합니다. 두 개의 스레드, 하나는 PipedInputStream을 작동하고 다른 하나는 PipedOutputStream을 작동합니다. PipedOutputStream이 작성한 데이터는 먼저 버퍼에 캐시됩니다. 버퍼가 가득 차면이 스레드는 대기합니다. PipedInputStream은 버퍼의 데이터를 읽습니다. 버퍼에 데이터가 없으면이 스레드는 대기합니다.
JDK1.5에서 대기열을 차단하여 동일한 함수를 달성 할 수 있습니다.
패키지 io; import java.io.*; public class pipedstreamtest {public static void main (string [] args) {pipedOutputStream ops = new PipedOutputStream (); PipedInputStream PIS = New PipedInputStream (); Ops.Connect (PIS); // new Producer (Ops); 소비자 (pis) .run ();} catch (예외 e) {e.printstacktrace ();}}} // 생산자 클래스 프로듀서는 runnable {private pipedoutputstream ops; public producer (pipedoutputstream ops) {this.ops = ops;} 공개 void를 구현합니다. run () {try {ops.write ( "hell, spell".getbytes ()); ops.close ();} catch (예외 e) {e.printstacktrace ();}}}} // 소비자 클래스 소비자는 runnable {private pipedinputstream pis; public consumer (pipedinputstream pis) {this. run () {try {byte [] bu = new byte [100]; int len = pis.read (bu); system.out.println (new String (bu, 0, len)); pis.close ();} catch (예외 e) {e.printstacktrace ();}}}예 2 : 위의 프로그램에 약간의 변경이 두 스레드가됩니다.
패키지 io; import java.io.*; public class pipedstreamtest {public static void main (string [] args) {pipedOutputStream ops = new PipedOutputStream (); PipedInputStream PIS = New PipedInputStream (); Ops.Connect (PIS); 새로운 Prapeline Connection Procather P = New Producer (OPS); 스레드 (p) .start (); 소비자 c = 새로운 소비자 (pis); new 스레드 (c) .Start ();} catch (예외 e) {e.printstacktrace ();}}}}} // 생산자 클래스 프로듀서는 런닝 가능한 {private pipedoutputstream ops; public problic producer (pipedoutputstream ops) {ops = ops;} run () {try {for (;;) {ops.write ( "hell, spell".getBytes ()); ops.close ();}} // 소비자 클래스 소비자 구현 런닝 가능 {private pipedInputStream pis; public consumer (pipedInputStream PIS) {this.pis = pis; bu = new Byte [100]; int len = pis.read (bu); system.out.println (new String (bu, 0, len));} pis.close ();} catch (예외 e) {e.printstacktrace ();}}}예 3.이 예제는 응용 프로그램에 더 적합합니다.
import java.io.*; public class pipedio {// 프로그램이 실행중인 후, sendfile 파일의 내용을 수신기 파일 파일에 공개 정적 무효 메인 (String args [])에 복사합니다 {try {// 파이프 라인 흐름 구조 파이프 라인 흐름 PipedInputStream (); 새로운 PipedoutStream (//); pos.connect (pis); // 두 개의 스레드를 구성하고 시작합니다. 새 발신자 (pos, "c :/rext2.txt"). start (); 새 수신기 (pis, "c :/rext3.txt"). start ();} catch (ioexcept e) {system.out.println ( "파이프 오류" + e);}}}}}}}}}}}}}}} {}}}}. sender (pipedoutputstream pos, String filename) {this.pos = pos; file = new File (filename);} // 스레드 run 메소드 public void run () {// 파일 내용 파일 컨텐츠 파일 파일 파일을 읽습니다. int data; while (data = fs.Read ()! =-1) pos.write (data);} pos.close ();} catch (ioexception e) {system.out.println ( "sender error" +e);}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}. filename);} // 스레드는 공개 void run () {try {// 파일 쓰기 스트림 객체 파일); int data; int data; // read ((data = pis.read ())! = -1) {// 로컬 파일 (data); e) {System.out.println ( "수신기 오류" +e);}}}7 차단 대기열
차단 큐는 파이프 라인 흐름 방법을 대체하여 입구/배수 파이프 모드 (생산자/소비자)를 구현할 수 있습니다. JDK1.5는 몇 가지 기성품 블로킹 대기열을 제공합니다. 이제 ArrayBlockingqueue 코드를 다음과 같이 살펴 보겠습니다.
다음은 차단 대기열입니다
Blockingqueue Blockingq = 새로운 ArrayBlockingqueue 10;
스레드는 줄에서 가져옵니다
for (;;) {object o = blockingq.take (); // 대기열이 비어있는 다음 대기 (차단)}}다른 스레드는 줄에 저장됩니다
for (;;) {blockingq.put (new Object ()); // 큐가 가득 찬 경우 대기 (차단)}}차단 대기열은 파이프 라인보다 사용하기가 더 간단하다는 것을 알 수 있습니다.
8 사용 집행자, 집행자, ExecutorService, ThreadPooleExecutor
스레드 관리 작업을 사용할 수 있습니다. JDK1.5에서 제공하는 클래스 세트를 사용하여 작업을보다 편리하게 관리 할 수 있습니다. 이러한 범주에서 우리는 작업 지향적 사고 방식을 경험할 수 있습니다. 이 수업은 다음과 같습니다.
집행자 인터페이스. 사용 방법 :
Executor Executor = anexecutor; // Executor 인스턴스를 생성합니다. Executor.Execute (New RunnableTask1 ());
의도 : 사용자는 작업 실행에만 초점을 맞추고 작업 작성 및 실행 세부 사항 및 타사 구현자가 우려하는 기타 문제에 대해 걱정할 필요가 없습니다. 즉, 작업 통화 실행 및 작업 구현을 해체합니다.
실제로 JDK1.5에는 이미이 인터페이스의 우수한 구현이 있습니다. 충분한.
집행자는 다양한 인터페이스의 인스턴스를 생성하는 데 사용되는 컬렉션과 같은 공장 클래스 또는 도구 클래스입니다.
ExecutorService 인터페이스는 Executor에서 상속됩니다. Executor는 실행을 위해 작업을 Executor ()에 버리고 나머지를 무시합니다. ExecutorService는 다르고 더 많은 제어 작업을 수행합니다. 예를 들어:
Class NetworkService {Private Final ServerSocket Servesocket; Private Final ExecutorService Pool; Public NetworkService (Int Port, Int Poolsize)는 ioException을 던졌습니다 {serversocket = new Serversocket (PORT); PORT = EXECUTORS.NEWFIXEDTHREADPOOL (POOLSIZE);} public void Serv () {for (;;) {PULL.Execute (새 신성) handler (serversocket.accept ()));}} catch (ioexception ex) {pool.shutdown (); // 새로운 작업이 실행되지 않습니다}}} 클래스 핸들러는 실행 가능 {개인 최종 소켓 소켓; 핸들러 (소켓) {this.socket = socket;ExecutorService (즉, 코드의 풀 객체)가 종료를 실행 한 후 더 이상 새 작업을 실행할 수 없지만 이전 작업은 계속 실행되며 실행을 기다리는 사람들은 더 이상 대기하지 않습니다.
작업 제출자 및 수행자 커뮤니케이션
public static void main (string args [])은 예외를 {exceusorService executor = executor = executor.newsingLethreadExecutor (); callable task = new Callable () {public string call () rows {return "test";}}; Future f = executor.submit (task); string result = f.get (blocking). System.out.println (결과); executor.shutdown ();}executors.newsingLethreadExecutor ()가 얻은 executor 인스턴스는 다음과 같은 특성을 가지고 있습니다.
작업 실행 순차적으로 실행됩니다. 예를 들어:
executor.submit (task1); executor.submit (task2);
Task2를 실행하기 전에 Task1을 실행할 때까지 기다려야합니다.
Task1 및 Task2는 큐에 배치되고 작업자 스레드에 의해 처리됩니다. 즉, 총 2 개의 스레드가 있습니다 (메인 스레드, 작업을 처리하는 작업자 스레드).
다른 수업은 Javadoc을 참조하십시오
9 동시 공정 제어
이 섹션의 예제는 Wen Shao의 Java Concurrency 튜토리얼에서 나와 변경 될 수 있습니다. 웬 씨에게 경의를 표합니다.
CountdownLatch 도어 핀 카운터
스레드를 시작하고 스레드가 끝날 때까지 기다립니다. 즉, 공통 기본 스레드 및 기타 하위 스레드는 기본 스레드의 끝에 실행됩니다.
public static void main (string [] args)은 예외를 던집니다 {// todo 자동 생성 메소드 스터브 최종 int count = 10; 최종 countdownlatch remallatch = new countdownlatch (count); // 도어 래치 수는 (int i = 0; i <count; i ++) {stride 스레드 = 새로운 스레드 ( "worker thread"{) {void run () {// do x x) {void run ( "void run () {// do x x. wemberelatch.countdown (); // 하나의 도어 래치를 줄이십시오}}}}}}}}}}}}}}}}}}}; thread.start ();} completelatch.await (); // 도어 래치가 아직 줄어들지 않은 경우 기다립니다. }JDK1.4에서 일반적인 방법은 자식 스레드의 상태를 설정하고 기본 스레드의 루프 감지를 설정하는 것입니다. 사용 편의성과 효율성은 좋지 않습니다.
많은 스레드를 시작하고 알림이 시작될 때까지 기다립니다
public static void main (string [] args)은 예외를 던집니다 {// todo 자동 생성 메소드 스터브 최종 Countdownlatch StartLatch = New CountdownLatch (1); // 도어 래치 (int i = 0; i <10; i ++) {스레드 스레드 = 새 스레드 ( "작업자 스레드"+i) {public void () {trytlatch. 아직 줄어드는} catch (InterruptedException e) {} // do xxxx}}; thread.start ();} startlatch.countdown (); // 한 도어 래치 감소}사이클리 버리어. 모든 스레드가 출발 선에 도달 한 후에 만 계속 실행할 수 있습니다.
공개 클래스 Cyclibarriertest는 런닝 가능한 {private cyclibarrier barrier; public cyclibarriertest (cyclibarrier barrier) {this.barrier = barrier;} public void run () {// do xxxx; try {this.barrier.await (); 스레드가 다른 스레드가 도착했는지 확인합니다. 도착하지 않으면 계속 기다리십시오. 모든 것이 도달하면 Barrier의 실행 기능 본체의 내용을 실행} catch (예외 e) {}}/** * @param args */public static void main (string [] args) {// parameter 2는 두 스레드가 함께 시작하기 전에 시작 라인에 도달했음을 의미합니다. xxxx;}}); 스레드 t1 = 새 스레드 (new cyclibarriertest (배리어)); 스레드 t2 = 새로운 스레드 (new cyclibarriertest (barrier)); t1.start (); t2.start ();}}이는 Coun
10 동시성 3 법
암델의 법칙. 문제 척도가 주어지면 병렬화 부품은 12%를 차지합니다. 그런 다음 병렬 처리가 극단에 적용 되더라도 시스템의 성능은 최대 1/(1-0.12) = 1.136 배만 향상 될 수 있습니다. 즉, 병렬 처리는 시스템 성능을 향상시키는 데 상한이 있습니다.
구스타프 슨의 법칙. Gustafson의 법칙에 따르면 Amdahl의 법칙은 CPU의 수가 증가함에 따라 더 많은 컴퓨팅 능력을 사용할 수 있다고 생각하지 않습니다. 본질은 문제의 척도를 변경하여 Amdahl의 법칙에서 연속 처리의 나머지 88%가 병렬화되어 성능 임계 값을 뚫을 수 있도록하는 것입니다. 본질적으로, 그것은 일종의 우주 교환 시간입니다.
선 법. 그것은 처음 두 법률의 추가 홍보입니다. 주요 아이디어는 컴퓨팅 속도가 CPU가 아닌 스토리지 속도로 제한된다는 것입니다. 따라서 저장 공간과 같은 컴퓨팅 리소스를 최대한 활용하고 더 나은/더 정확한 솔루션을 생산하기 위해 문제의 규모를 높이려고 노력해야합니다.
11 동시에서 평행까지
칩이 뜨거워 지도록 객체를 식별 할 때 컴퓨터는 신속하게 계산해야합니다. 사람들이 물체를 인식 할 때, 그들은 한 눈에 분명하지만, 특정 뇌 세포를 태워 (과장)하고 불편 함을 느끼지 않습니다. 이것은 뇌가 분산 된 병렬 작동 시스템이기 때문입니다. Google이 저렴한 Linux 서버를 사용하여 거대하고 복잡한 계산을 수행 할 수있는 것처럼, 뇌의 수많은 뉴런은 독립적으로 계산하고, 서로 결과를 공유하며, 단일 CPU에 대한 수조 작업이 필요한 효과를 즉시 완료합니다. 병렬 처리 분야에서 생성되면 컴퓨터의 개발과 미래에 헤아릴 수없는 영향을 미칠 것이라고 상상해보십시오. 물론, 도전도 상상할 수 있습니다. 많은 문제가 쉽게 "나뉘어져 있지 않습니다".
요약
위는 Java 동시성 문제에 대한이 기사의 전체 내용이며, 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!