java多線程問題
Ⅰ 一個關於java多線程的問題
javadoc THREAD
t.start();
使該線程開始執行;Java 虛擬機調用該線程的 run 方法。
結果是兩個線程並發地運行;當前線程(從調用返回給 start 方法)和另一個線程(執行其 run 方法)。
多次啟動一個線程是非法的。特別是當線程已經結束執行後,不能再重新啟動。
t.run();
如果該線程是使用獨立的Runnable運行構造的,則調用該Runnable對象的run方法。如果這個類是一個線程類,只要啟動線程,就會執行run()方法。
說白了就是run直接調用介面的run方法
而start是調用兩次,start的線程和run方法的線程!
Ⅱ 什麼是Java多線程
多線程的概念?
說起多線程,那麼就不得不說什麼是線程,而說起線程,又不得不說什麼是進程。
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
進程可以簡單的理解為一個可以獨立運行的程序單位。它是線程的集合,進程就是有一個或多個線程構成的,每一個線程都是進程中的一條執行路徑。
那麼多線程就很容易理解:多線程就是指一個進程中同時有多個執行路徑(線程)正在執行。
為什麼要使用多線程?
1.在一個程序中,有很多的操作是非常耗時的,如資料庫讀寫操作,IO操作等,如果使用單線程,那麼程序就必須等待這些操作執行完成之後才能執行其他操作。使用多線程,可以在將耗時任務放在後台繼續執行的同時,同時執行其他操作。
2.可以提高程序的效率。
3.在一些等待的任務上,如用戶輸入,文件讀取等,多線程就非常有用了。
缺點:
1.使用太多線程,是很耗系統資源,因為線程需要開辟內存。更多線程需要更多內存。
2.影響系統性能,因為操作系統需要在線程之間來回切換。
3.需要考慮線程操作對程序的影響,如線程掛起,中止等操作對程序的影響。
4.線程使用不當會發生很多問題。
總結:多線程是非同步的,但這不代表多線程真的是幾個線程是在同時進行,實際上是系統不斷地在各個線程之間來回的切換(因為系統切換的速度非常的快,所以給我們在同時運行的錯覺)。
2.多線程與高並發的聯系。
高並發:高並發指的是一種系統運行過程中遇到的一種「短時間內遇到大量操作請求」的情況,主要發生在web系統集中大量訪問或者socket埠集中性收到大量請求(例如:12306的搶票情況;天貓雙十一活動)。該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,資料庫的操作等。如果高並發處理不好,不僅僅降低了用戶的體驗度(請求響應時間過長),同時可能導致系統宕機,嚴重的甚至導致OOM異常,系統停止工作等。如果要想系統能夠適應高並發狀態,則需要從各個方面進行系統優化,包括,硬體、網路、系統架構、開發語言的選取、數據結構的運用、演算法優化、資料庫優化……。
而多線程只是在同/非同步角度上解決高並發問題的其中的一個方法手段,是在同一時刻利用計算機閑置資源的一種方式。
多線程在高並發問題中的作用就是充分利用計算機資源,使計算機的資源在每一時刻都能達到最大的利用率,不至於浪費計算機資源使其閑置。
3.線程的創建,停止,常用方法介紹。
1.線程的創建:
線程創建主要有2種方式,一種是繼承Thread類,重寫run方法即可;(Thread類實現了Runable介面)
另一種則是實現Runable介面,也需要重寫run方法。
線程的啟動,調用start()方法即可。 我們也可以直接使用線程對象的run方法,不過直接使用,run方法就只是一個普通的方法了。
其他的還有: 通過匿名內部類的方法創建;實現Callable介面。。。。。
2.線程常用方法:
currentThread()方法:該方法返回當前線程的信息 .getName()可以返回線程名稱。
isAlive()方法:該方法判斷當前線程是否處於活動狀態。
sleep()方法:該方法是讓「當前正在執行的線程「休眠指定的時間,正在執行的線程是指this.currentThread()返回的線程。
getId()方法:該方法是獲取線程的唯一標識。
3.線程的停止:
在java中,停止線程並不簡單,不想for。。break那樣說停就停,需要一定的技巧。
線程的停止有3種方法:
1.線程正常終止,即run()方法運行結束正常停止。
2.使用interrupt方法中斷線程。
3.使用stop方法暴力停止線程。
interrupt方法中斷線程介紹:
interrupt方法其實並不是直接中斷線程,只是給線程添加一個中斷標志。
判斷線程是否是停止狀態:
this.interrupted(); 判斷當前線程是否已經中斷。(判斷的是這個方法所在的代碼對應的線程,而不是調用對象對應的線程)
this.isInterrupted(); 判斷線程是否已經中斷。(誰調用,判斷誰)
註:.interrupted()與isInterrupted()的區別:
interrupted()方法判斷的是所在代碼對應的線程是否中斷,而後者判斷的是調用對象對應的線程是否停止
前者執行後有清除狀態的功能(如連續調用兩次時,第一次返回true,則第二次會返回false)
後者沒有清除狀態的功能(兩次返回都為true)
真正停止線程的方法:
異常法:
在run方法中 使用 this.interrupted();判斷線程終止狀態,如果為true則 throw new interruptedException()然後捕獲該異常即可停止線程。
return停止線程:
在run方法中 使用 this.interrupted();判斷線程終止狀態,如果為true則return停止線程。 (建議使用異常法停止線程,因為還可以在catch中使線程向上拋,讓線程停止的事件得以傳播)。
暴力法:
使用stop()方法強行停止線程(強烈不建議使用,會造成很多不可預估的後果,已經被標記為過時)
(使用stop方法會拋出 java.lang.ThreadDeath 異常,並且stop方法會釋放鎖,很容易造成數據不一致)
註:在休眠中停止線程:
在sleep狀態下停止線程 會報異常,並且會清除線程狀態值為false;
先停止後sleep,同樣會報異常 sleep interrupted;
4.守護線程。
希望對您有所幫助!~
Ⅲ 如何解決java 多線程問題
Java線程同步需要我們不斷的進行相關知識的學習,下面我們就來看看如何才能更好的在學習中掌握相關的知識訊息,來完善我們自身的編寫手段。希望大家有所收獲。 Java線程同步的優先順序代表該線程的重要程度,當有多個線程同時處於可執行狀態並等待獲得 CPU 時間時,線程調度系統根據各個線程的優先順序來決定給誰分配 CPU 時間,優先順序高的線程有更大的機會獲得 CPU 時間,優先順序低的線程也不是沒有機會,只是機會要小一些罷了。 你可以調用 Thread 類的方法 getPriority()和 setPriority()來存取Java線程同步的優先順序,線程的優先順序界於1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,預設是5(NORM_PRIORITY)。 Java線程同步 由於同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。 由於我們可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。 1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:1. public synchronized void accessVal(int newVal); synchronized 方法控制對類成員變數的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的Java線程同步方能獲得該鎖,重新進入可執行狀態。 這種機制確保了同一時刻對於每一個類實例,其所有聲明為 synchronized 的成員函數中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變數的訪問沖突(只要所有可能訪問類成員變數的方法均被聲明為 synchronized)。 在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變數的訪問。 synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run()聲明為 synchronized ,由於在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變數的代碼放到專門的方法中,將其聲明為 synchronized ,並在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。 2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。語法如下:1. synchronized(syncObject)2. {3. //允許訪問控制的代碼4. } synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由於可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。 Java線程同步的阻塞 為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個Java線程同步對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經准備好了被訪問,反過來,同一時刻准備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持。 阻塞指的是暫停一個Java線程同步的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。
Ⅳ java多線程問題
這是因為你沒有處理並發問題
先說下 num-- ,這個過程也是可以拆分的:
從內存中取出num的值
num - 1
將減1後的值重新賦值給num(即放回內存)
下面以一個例子說明,為什麼有可能會出現多個100
因為你沒有做同步,所以線程t1和t2可能在同一瞬間執行到num--處,假設這剛好是程序開始的時候num還等於100。然後來看剛剛拆解的num--的過程。
t1取出了num的值,t2也同時取出了num的值,因為是同時,所以他們取到的都是100。
然後System.out.println輸出的 num--,所以會輸出num當前的值(減1前的值),在t1和t2看來 num現在都是100,所以會輸出2次100。
接下來t1執行減1操作,並將結果99賦值給num。同時t2也執行減1操作,並將結果99賦值給num。
最終,雖然t1和t2都執行了num--,但是最終num的值卻是99,這與預期肯定是不一樣的。
這也就是編程中要處理的多線程並發問題。
Ⅳ Java多線程問題
線程之間的上下文切換也是需要cpu時間的。
最主要的是,一般來說在多核cpu下,多線程的效率是比單線程的高,但是這個高是建立在利用了空閑的cpu,因為一般來說cpu使用率都不很高,你這個程序的話,cpu使用已經很高了,多線程並不能讓你的效率變高,反而因為上下文切換導致變低,關鍵在於理解多線程一般為什麼會使效率變高。
Ⅵ 關於java中多線程的問題的一點思考(什麼情
1,理解正確,幾個線程各子鎖定自己的同步鎖,當然是沒有什麼用。對於競爭資源,必須鎖定同一個鎖,你可以new 一個Object用於鎖,也可以用class做鎖,反正都要是同一個。
2,理解有偏差,其他線程也會被調度,不可能一個線程一直sleep,其他線程都不工作了,影響范圍沒有那麼大,僅限於需要進入同一個同步鎖的,它們進不了工作。
所謂占著茅坑不拉shi,就是這個狀態了。
3,多線程的好處是充分利用CPU的資源,實現並發。例如你說的通訊,往往是花百分之幾的時間CPU處理數據,剩下的絕大部分時間,都是在等待網路數據。使用多線程可以充分利用這段時間。
Ⅶ java 多線程問題
你的設計只是一個單例模式,但是也是有問題
public static Singleton getInstance() {
if(singleton == null)
return new Singleton(); //始終沒有給singleton賦值啊
else
return singleton;
}
可以改為return singleton=new Singleton();
這樣也有個問題 --(昨天有點事,沒有說完!)如果一個線程判斷singleton為null還沒有來的及賦值就被暫停,剛好另一個線程也運行此處給singleton賦值了,等前一個線程開始執行時就會再賦值一次。應該在加一個synchronized(this)加鎖!有點復雜,可以定義singleton 時賦值getInstance直接返回這個值就可以了.
關於多處理器的問題,我個人覺的應該是由操作系統來負責調度,我們不用去關心,所有的程序時運行在java虛擬機上的,我們只關心虛擬機就可以了。
如果運行在多伺服器上,那就應該需要的多虛擬機的同步了......這個我也沒有研究過,愛莫能助
請採納。
Ⅷ 多線程java問題
在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面。實現Runnable介面比繼承Thread類所具有的優勢:1):適合多個相同的程序代碼的線程去處理同一個資源2):可以避免java中的單繼承的限制3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用java命令執行一個類的時候,實際上都會啟動一個JVM,每一個jVM實習在就是在操作系統中啟動了一個進程。
Ⅸ java多線程的問題
import java.util.concurrent.ArrayBlockingQueue;
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue(1000);
queue.put("123");
Object value = queue.take();
System.out.println(value);
}
}
你的這個問題,是大部分多線程程序都會遇到的問題,因為JDK類庫的開發者已經為我們准備了很多「隊列」。
你可以考慮「先進先出阻塞隊列」。
ArrayBlockingQueue<E>
一個由數組支持的有界阻塞隊列。此隊列按FIFO(先進先出)原則對元素進行排序。隊列的頭部是在隊列中存在時間最長的元素。隊列的尾部是在隊列中存在時間最短的元素。新元素插入到隊列的尾部,隊列獲取操作則是從隊列頭部開始獲得元素。
這是一個典型的「有界緩存區」,固定大小的數組在其中保持生產者插入的元素和使用者提取的元素。一旦創建了這樣的緩存區,就不能再增加其容量。試圖向已滿隊列中放入元素會導致操作受阻塞;試圖從空隊列中提取元素將導致類似阻塞。
一些重要的方法:
boolean add(Ee) 將指定的元素插入到此隊列的尾部(如果立即可行且不會超過該隊列的容量),在成功時返回true,如果此隊列已滿,則拋出IllegalStateException。
boolean offer(Ee) 將指定的元素插入到此隊列的尾部(如果立即可行且不會超過該隊列的容量),在成功時返回true,如果此隊列已滿,則返回false。
boolean offer(Ee,longtimeout,TimeUnitunit) 將指定的元素插入此隊列的尾部,如果該隊列已滿,則在到達指定的等待時間之前等待可用的空間。
void put(Ee) 將指定的元素插入此隊列的尾部,如果該隊列已滿,則等待可用的空間。
----
E remove() 獲取並移除此隊列的頭。
E poll() 獲取並移除此隊列的頭,如果此隊列為空,則返回null。
E poll(longtimeout,TimeUnitunit) 獲取並移除此隊列的頭部,在指定的等待時間前等待可用的元素(如果有必要)。
E take() 獲取並移除此隊列的頭部,在元素變得可用之前一直等待(如果有必要)。