您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)java中并發(fā)問(wèn)題的示例分析,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
1什么是并發(fā)問(wèn)題。
多個(gè)進(jìn)程或線程同時(shí)(或著說(shuō)在同一段時(shí)間內(nèi))訪問(wèn)同一資源會(huì)產(chǎn)生并發(fā)問(wèn)題。
銀行兩操作員同時(shí)操作同一賬戶就是典型的例子。比如A、B操作員同時(shí)讀取一余額為1000元的賬戶,A操作員為該賬戶增加100元,B操作員同時(shí)為該賬戶減去50元,A先提交,B后提交。最后實(shí)際賬戶余額為1000-50=950元,但本該為1000+100-50=1050。這就是典型的并發(fā)問(wèn)題。如何解決?可以用鎖。
2java中synchronized的用法
用法1
public class Test{ public synchronized void print(){ ….; } }
某線程執(zhí)行print()方法,則該對(duì)象將加鎖。其它線程將無(wú)法執(zhí)行該對(duì)象的所有synchronized塊。
用法2
public class Test{ public void print(){ synchronized(this){ //鎖住本對(duì)象 …; } } }
同用法1, 但更能體現(xiàn)synchronized用法的本質(zhì)。
用法3
public class Test{ private String a = “test”; public void print(){ synchronized(a){ //鎖住a對(duì)象 …; } } public synchronized void t(){ …; //這個(gè)同步代碼塊不會(huì)因?yàn)閜rint()而鎖定. } }
執(zhí)行print(),會(huì)給對(duì)象a加鎖,注意不是給Test的對(duì)象加鎖,也就是說(shuō)Test對(duì)象的其它synchronized方法不會(huì)因?yàn)閜rint()而被鎖。同步代碼塊執(zhí)行完,則釋放對(duì)a的鎖。
為了鎖住一個(gè)對(duì)象的代碼塊而不影響該對(duì)象其它synchronized塊的高性能寫法:
public class Test{ private byte[] lock = new byte[0]; public void print(){ synchronized(lock){ …; } } public synchronized void t(){ …; } }
靜態(tài)方法的鎖
public class Test{ public synchronized static void execute(){ …; } }
效果同
public class Test{ public static void execute(){ synchronized(TestThread.class){ …; } } }
3 Java中的鎖與排隊(duì)上廁所。
鎖就是阻止其它進(jìn)程或線程進(jìn)行資源訪問(wèn)的一種方式,即鎖住的資源不能被其它請(qǐng)求訪問(wèn)。在JAVA中,sychronized關(guān)鍵字用來(lái)對(duì)一個(gè)對(duì)象加鎖。比如:
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(); /** 下面對(duì)象m被加鎖。嚴(yán)格的說(shuō)是對(duì)象m的所有synchronized塊被加鎖。 如果存在另一個(gè)試圖訪問(wèn)m的線程T,那么T無(wú)法執(zhí)行m對(duì)象的push和 pop方法。 */ m.pop(); //對(duì)象m被加鎖。 } }
Java的加鎖解鎖跟多個(gè)人排隊(duì)等一個(gè)公共廁位完全一樣。第一個(gè)人進(jìn)去后順手把門從里面鎖住,其它人只好排隊(duì)等。第一個(gè)人結(jié)束后出來(lái)時(shí),門才會(huì)打開(解鎖)。輪到第二個(gè)人進(jìn)去,同樣他又會(huì)把門從里面鎖住,其它人繼續(xù)排隊(duì)等待。
用廁所理論可以很容易明白:一個(gè)人進(jìn)了一個(gè)廁位,這個(gè)廁位就會(huì)鎖住,但不會(huì)導(dǎo)致另一個(gè)廁位也被鎖住,因?yàn)橐粋€(gè)人不能同時(shí)蹲在兩個(gè)廁位里。對(duì)于Java就是說(shuō):Java中的鎖是針對(duì)同一個(gè)對(duì)象的,不是針對(duì)class的??聪吕?/p>
MyStatckm1=newMyStack(); MyStatckm2=newMystatck(); m1.pop(); m2.pop();
m1對(duì)象的鎖是不會(huì)影響m2的鎖的,因?yàn)樗鼈儾皇峭粋€(gè)廁位。就是說(shuō),假設(shè)有3線程t1,t2,t3操作m1,那么這3個(gè)線程只可能在m1上排隊(duì)等,假設(shè)另2個(gè)線程t8,t9在操作m2,那么t8,t9只會(huì)在m2上等待。而t2和t8則沒(méi)有關(guān)系,即使m2上的鎖釋放了,t1,t2,t3可能仍要在m1上排隊(duì)。原因無(wú)它,不是同一個(gè)廁位耳。
Java不能同時(shí)對(duì)一個(gè)代碼塊加兩個(gè)鎖,這和數(shù)據(jù)庫(kù)鎖機(jī)制不同,數(shù)據(jù)庫(kù)可以對(duì)一條記錄同時(shí)加好幾種不同的鎖。
4何時(shí)釋放鎖?
一般是執(zhí)行完畢同步代碼塊(鎖住的代碼塊)后就釋放鎖,也可以用wait()方式半路上釋放鎖。wait()方式就好比蹲廁所到一半,突然發(fā)現(xiàn)下水道堵住了,不得已必須出來(lái)站在一邊,好讓修下水道師傅(準(zhǔn)備執(zhí)行notify的一個(gè)線程)進(jìn)去疏通馬桶,疏通完畢,師傅大喊一聲:“已經(jīng)修好了”(notify),剛才出來(lái)的同志聽到后就重新排隊(duì)。注意啊,必須等師傅出來(lái)啊,師傅不出來(lái),誰(shuí)也進(jìn)不去。也就是說(shuō)notify后,不是其它線程馬上可以進(jìn)入封鎖區(qū)域活動(dòng)了,而是必須還要等notify代碼所在的封鎖區(qū)域執(zhí)行完畢從而釋放鎖以后,其它線程才可進(jìn)入。
這里是wait與notify代碼示例:
public synchronized char pop() { char c; while (buffer.size() == 0) { try { this.wait(); //從廁位里出來(lái) } catch (InterruptedException e) { // ignore it… } } c = ((Character)buffer.remove(buffer.size()-1)). charValue(); return c; } public synchronized void push(char c) { this.notify(); //通知那些wait()的線程重新排隊(duì)。注意:僅僅是通知它們重新排隊(duì)。 Character charObj = new Character(c); buffer.addElement(charObj); } //執(zhí)行完畢,釋放鎖。那些排隊(duì)的線程就可以進(jìn)來(lái)了。
再深入一些。
由于wait()操作而半路出來(lái)的同志沒(méi)收到notify信號(hào)前是不會(huì)再排隊(duì)的,他會(huì)在旁邊看著這些排隊(duì)的人(其中修水管師傅也在其中)。注意,修水管的師傅不能插隊(duì),也得跟那些上廁所的人一樣排隊(duì),不是說(shuō)一個(gè)人蹲了一半出來(lái)后,修水管師傅就可以突然冒出來(lái)然后立刻進(jìn)去搶修了,他要和原來(lái)排隊(duì)的那幫人公平競(jìng)爭(zhēng),因?yàn)樗彩莻€(gè)普通線程。如果修水管師傅排在后面,則前面的人進(jìn)去后,發(fā)現(xiàn)堵了,就wait,然后出來(lái)站到一邊,再進(jìn)去一個(gè),再wait,出來(lái),站到一邊,只到師傅進(jìn)去執(zhí)行notify.這樣,一會(huì)兒功夫,排隊(duì)的旁邊就站了一堆人,等著notify.
終于,師傅進(jìn)去,然后notify了,接下來(lái)呢?
1.有一個(gè)wait的人(線程)被通知到。
2.為什么被通知到的是他而不是另外一個(gè)wait的人?取決于JVM.我們無(wú)法預(yù)先
判斷出哪一個(gè)會(huì)被通知到。也就是說(shuō),優(yōu)先級(jí)高的不一定被優(yōu)先喚醒,等待
時(shí)間長(zhǎng)的也不一定被優(yōu)先喚醒,一切不可預(yù)知!(當(dāng)然,如果你了解該JVM的
實(shí)現(xiàn),則可以預(yù)知)。
3.他(被通知到的線程)要重新排隊(duì)。
4.他會(huì)排在隊(duì)伍的第一個(gè)位置嗎?回答是:不一定。他會(huì)排最后嗎?也不一定。
但如果該線程優(yōu)先級(jí)設(shè)的比較高,那么他排在前面的概率就比較大。
5.輪到他重新進(jìn)入廁位時(shí),他會(huì)從上次wait()的地方接著執(zhí)行,不會(huì)重新執(zhí)行。
惡心點(diǎn)說(shuō)就是,他會(huì)接著拉巴巴,不會(huì)重新拉。
6.如果師傅notifyAll().則那一堆半途而廢出來(lái)的人全部重新排隊(duì)。順序不可知。
JavaDOC上說(shuō),Theawakenedthreadswillnotbeabletoproceeduntilthecurrentthreadrelinquishesthelockonthisobject(當(dāng)前線程釋放鎖前,喚醒的線程不能去執(zhí)行)。
這用廁位理論解釋就是顯而易見的事。
5Lock的使用
用synchronized關(guān)鍵字可以對(duì)資源加鎖。用Lock關(guān)鍵字也可以。它是JDK1.5中新增內(nèi)容。用法如下:
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(); } } }
(注:這是JavaDoc里的例子,是一個(gè)阻塞隊(duì)列的實(shí)現(xiàn)例子。所謂阻塞隊(duì)列,就是一個(gè)隊(duì)列如果滿了或者空了,都會(huì)導(dǎo)致線程阻塞等待。Java里的ArrayBlockingQueue提供了現(xiàn)成的阻塞隊(duì)列,不需要自己專門再寫一個(gè)了。)
一個(gè)對(duì)象的lock.lock()和lock.unlock()之間的代碼將會(huì)被鎖住。這種方式比起synchronize好在什么地方?簡(jiǎn)而言之,就是對(duì)wait的線程進(jìn)行了分類。用廁位理論來(lái)描述,則是那些蹲了一半而從廁位里出來(lái)等待的人原因可能不一樣,有的是因?yàn)轳R桶堵了,有的是因?yàn)轳R桶沒(méi)水了。通知(notify)的時(shí)候,就可以喊:因?yàn)轳R桶堵了而等待的過(guò)來(lái)重新排隊(duì)(比如馬桶堵塞問(wèn)題被解決了),或者喊,因?yàn)轳R桶沒(méi)水而等待的過(guò)來(lái)重新排隊(duì)(比如馬桶沒(méi)水問(wèn)題被解決了)。這樣可以控制得更精細(xì)一些。不像synchronize里的wait和notify,不管是馬桶堵塞還是馬桶沒(méi)水都只能喊:剛才等待的過(guò)來(lái)排隊(duì)!假如排隊(duì)的人進(jìn)來(lái)一看,發(fā)現(xiàn)原來(lái)只是馬桶堵塞問(wèn)題解決了,而自己渴望解決的問(wèn)題(馬桶沒(méi)水)還沒(méi)解決,只好再回去等待(wait),白進(jìn)來(lái)轉(zhuǎn)一圈,浪費(fèi)時(shí)間與資源。
Lock方式與synchronized對(duì)應(yīng)關(guān)系:
LockawaitsignalsignalAll
synchronizedwaitnotifynotifyAll
注意:不要在Lock方式鎖住的塊里調(diào)用wait、notify、notifyAll
6利用管道進(jìn)行線程間通信
原理簡(jiǎn)單。兩個(gè)線程,一個(gè)操作PipedInputStream,一個(gè)操作PipedOutputStream。PipedOutputStream寫入的數(shù)據(jù)先緩存在Buffer中,如果Buffer滿,此線程wait。PipedInputStream讀出Buffer中的數(shù)據(jù),如果Buffer沒(méi)數(shù)據(jù),此線程wait。
jdk1.5中的阻塞隊(duì)列可實(shí)現(xiàn)同樣功能。
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); //實(shí)現(xiàn)管道連接 new Producer(ops).run(); new Consumer(pis).run(); } catch(Exception e){ e.printStackTrace(); } } } //生產(chǎn)者 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(); } } } //消費(fèi)者 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(); } } }
例2 對(duì)上面的程序做少許改動(dòng)就成了兩個(gè)線程。
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); //實(shí)現(xiàn)管道連接 Producer p = new Producer(ops); new Thread(p).start(); Consumer c = new Consumer(pis); new Thread(c).start(); } catch(Exception e){ e.printStackTrace(); } } } //生產(chǎn)者 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(); } } } //消費(fèi)者 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(); } } }
例3. 這個(gè)例子更加貼進(jìn)應(yīng)用
import java.io.*; public class PipedIO { //程序運(yùn)行后將sendFile文件的內(nèi)容拷貝到receiverFile文件中 public static void main(String args[]){ try{ //構(gòu)造讀寫的管道流對(duì)象 PipedInputStream pis=new PipedInputStream(); PipedOutputStream pos=new PipedOutputStream(); //實(shí)現(xiàn)關(guān)聯(lián) pos.connect(pis); //構(gòu)造兩個(gè)線程,并且啟動(dòng)。 new Sender(pos,”c:\text2.txt”).start(); new Receiver(pis,”c:\text3.txt”).start(); } catch(IOException e){ System.out.println(“Pipe Error”+ e); } } } //線程發(fā)送 class Sender extends Thread{ PipedOutputStream pos; File file; //構(gòu)造方法 Sender(PipedOutputStream pos, String fileName){ this.pos=pos; file=new File(fileName); } //線程運(yùn)行方法 public void run(){ try{ //讀文件內(nèi)容 FileInputStream fs=new FileInputStream(file); int data; while((data=fs.read())!=-1){ //寫入管道始端 pos.write(data); } pos.close(); } catch(IOException e) { System.out.println(“Sender Error” +e); } } } //線程讀 class Receiver extends Thread{ PipedInputStream pis; File file; //構(gòu)造方法 Receiver(PipedInputStream pis, String fileName){ this.pis=pis; file=new File(fileName); } //線程運(yùn)行 public void run(){ try { //寫文件流對(duì)象 FileOutputStream fs=new FileOutputStream(file); int data; //從管道末端讀 while((data=pis.read())!=-1){ //寫入本地文件 fs.write(data); } pis.close(); } catch(IOException e){ System.out.println("Receiver Error" +e); } } }
7阻塞隊(duì)列
阻塞隊(duì)列可以代替管道流方式來(lái)實(shí)現(xiàn)進(jìn)水管/排水管模式(生產(chǎn)者/消費(fèi)者).JDK1.5提供了幾個(gè)現(xiàn)成的阻塞隊(duì)列.現(xiàn)在來(lái)看ArrayBlockingQueue的代碼如下:
這里是一個(gè)阻塞隊(duì)列
BlockingQueue blockingQ = new ArrayBlockingQueue 10;
一個(gè)線程從隊(duì)列里取
for(;;){ Object o = blockingQ.take();//隊(duì)列為空,則等待(阻塞) }
另一個(gè)線程往隊(duì)列存
for(;;){ blockingQ.put(new Object());//隊(duì)列滿,則等待(阻塞) }
可見,阻塞隊(duì)列使用起來(lái)比管道簡(jiǎn)單。
8使用Executors、Executor、ExecutorService、ThreadPoolExecutor
可以使用線程管理任務(wù)。還可以使用jdk1.5提供的一組類來(lái)更方便的管理任務(wù)。從這些類里我們可以體會(huì)一種面向任務(wù)的思維方式。這些類是:
Executor接口。使用方法:
Executor executor = anExecutor;//生成一個(gè)Executor實(shí)例。 executor.execute(new RunnableTask1());
用意:使用者只關(guān)注任務(wù)執(zhí)行,不用操心去關(guān)注任務(wù)的創(chuàng)建、以及執(zhí)行細(xì)節(jié)等這些第三方實(shí)現(xiàn)者關(guān)心的問(wèn)題。也就是說(shuō),把任務(wù)的調(diào)用執(zhí)行和任務(wù)的實(shí)現(xiàn)解耦。
實(shí)際上,JDK1.5中已經(jīng)有該接口出色的實(shí)現(xiàn)。夠用了。
Executors是一個(gè)如同Collections一樣的工廠類或工具類,用來(lái)產(chǎn)生各種不同接口的實(shí)例。
ExecutorService接口它繼承自Executor.Executor只管把任務(wù)扔進(jìn)executor()里去執(zhí)行,剩余的事就不管了。而ExecutorService則不同,它會(huì)多做點(diǎn)控制工作。比如:
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(); //不再執(zhí)行新任務(wù) } } } class Handler implements Runnable { private final Socket socket; Handler(Socket socket) { this.socket = socket; } public void run() { // read and service request } }
ExecutorService(也就是代碼里的pool對(duì)象)執(zhí)行shutdown后,它就不能再執(zhí)行新任務(wù)了,但老任務(wù)會(huì)繼續(xù)執(zhí)行完畢,那些等待執(zhí)行的任務(wù)也不再等待了。
任務(wù)提交者與執(zhí)行者通訊
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(); //等待(阻塞)返回結(jié)果 System.out.println(result); executor.shutdown(); }
Executors.newSingleThreadExecutor()取得的Executor實(shí)例有以下特性:
任務(wù)順序執(zhí)行.比如:
executor.submit(task1); executor.submit(task2);
必須等task1執(zhí)行完,task2才能執(zhí)行。
task1和task2會(huì)被放入一個(gè)隊(duì)列里,由一個(gè)工作線程來(lái)處理。即:一共有2個(gè)線程(主線程、處理任務(wù)的工作線程)。
其它的類請(qǐng)參考JavaDoc
9并發(fā)流程控制
本節(jié)例子來(lái)自溫少的Java并發(fā)教程,可能會(huì)有改動(dòng)。向溫少致敬。
CountDownLatch門插銷計(jì)數(shù)器
啟動(dòng)線程,然后等待線程結(jié)束。即常用的主線程等所有子線程結(jié)束后再執(zhí)行的問(wèn)題。
public static void main(String[] args)throws Exception { // TODO Auto-generated method stub final int count=10; final CountDownLatch completeLatch = new CountDownLatch(count); //定義了門插銷的數(shù)目是10 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(); //如果門插銷還沒(méi)減完則等待。 }
JDK1.4時(shí),常用辦法是給子線程設(shè)置狀態(tài),主線程循環(huán)檢測(cè)。易用性和效率都不好。
啟動(dòng)很多線程,等待通知才能開始
public static void main(String[] args) throws Exception { // TODO Auto-generated method stub 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(); //如果門插銷還沒(méi)減完則等待 } catch (InterruptedException e) { } // do xxxx } } ; thread.start(); } startLatch.countDown(); //減少一根門插銷 }
CycliBarrier. 等所有線程都達(dá)到一個(gè)起跑線后才能開始繼續(xù)運(yùn)行。
public class CycliBarrierTest implements Runnable { private CyclicBarrier barrier; public CycliBarrierTest(CyclicBarrier barrier) { this.barrier = barrier; } public void run() { //do xxxx; try { this.barrier.await(); //線程運(yùn)行至此會(huì)檢查是否其它線程都到齊了,沒(méi)到齊就繼續(xù)等待。到齊了就執(zhí)行barrier的run函數(shù)體里的內(nèi)容 } catch (Exception e) { } } /** * @param args */ public static void main(String[] args) { //參數(shù)2代表兩個(gè)線程都達(dá)到起跑線才開始一起繼續(xù)往下執(zhí)行 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(); } }
這簡(jiǎn)化了傳統(tǒng)的用計(jì)數(shù)器+wait/notifyAll來(lái)實(shí)現(xiàn)該功能的方式。
10并發(fā)3定律
Amdahl定律.給定問(wèn)題規(guī)模,可并行化部分占12%,那么即使把并行運(yùn)用到極致,系統(tǒng)的性能最多也只能提高1/(1-0.12)=1.136倍。即:并行對(duì)提高系統(tǒng)性能有上限。
Gustafson定律.Gustafson定律說(shuō)Amdahl定律沒(méi)有考慮隨著cpu的增多而有更多的計(jì)算能力可被使用。其本質(zhì)在于更改問(wèn)題規(guī)模從而可以把Amdahl定律中那剩下的88%的串行處理并行化,從而可以突破性能門檻。本質(zhì)上是一種空間換時(shí)間。
Sun-Ni定律.是前兩個(gè)定律的進(jìn)一步推廣。其主要思想是計(jì)算的速度受限于存儲(chǔ)而不是CPU的速度.所以要充分利用存儲(chǔ)空間等計(jì)算資源,盡量增大問(wèn)題規(guī)模以產(chǎn)生更好/更精確的解.
11由并發(fā)到并行
計(jì)算機(jī)識(shí)別物體需要飛速的計(jì)算,以至于芯片發(fā)熱發(fā)燙,而人在識(shí)別物體時(shí)卻一目了然,卻并不會(huì)導(dǎo)致某個(gè)腦細(xì)胞被燒熱燒焦(夸張)而感到不適,是由于大腦是一個(gè)分布式并行運(yùn)行系統(tǒng),就像google用一些廉價(jià)的linux服務(wù)器可以進(jìn)行龐大復(fù)雜的計(jì)算一樣,大腦內(nèi)部無(wú)數(shù)的神經(jīng)元的獨(dú)自計(jì)算,互相分享成果,從而瞬間完成需要單個(gè)cpu萬(wàn)億次運(yùn)算才能有的效果。試想,如果在并行處理領(lǐng)域有所創(chuàng)建,將對(duì)計(jì)算機(jī)的發(fā)展和未來(lái)產(chǎn)生不可估量的影響。當(dāng)然,其中的挑戰(zhàn)也可想而知:許多的問(wèn)題是并不容易輕易就“分割”的了的。
關(guān)于“java中并發(fā)問(wèn)題的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。