java線程間通信
A. java線程間通信的幾種方式
Java多線程間的通信
Java還提供了一種線程間通信的機制,這種通信通什麼實現?
wait,notify等機制
或使用pipeInputStream和pipeOutputStream
1. 線程的幾種狀態
線程有四種狀態,任何一個線程肯定處於這四種狀態中的一種:
1) 產生(New):線程對象已經產生,但尚未被啟動,所以無法執行。如通過new產生了一個線程對象後沒對它調用start()函數之前。
2) 可執行(Runnable):每個支持多線程的系統都有一個排程器,排程器會從線程池中選擇一個線程並啟動它。當一個線程處於可執行狀態時,表示它可能正處於線程池中等待排排程器啟動它;也可能它已正在執行。如執行了一個線程對象的start()方法後,線程就處於可執行狀態,但顯而易見的是此時線程不一定正在執行中。
3) 死亡(Dead):當一個線程正常結束,它便處於死亡狀態。如一個線程的run()函數執行完畢後線程就進入死亡狀態。
4) 停滯(Blocked):當一個線程處於停滯狀態時,系統排程器就會忽略它,不對它進行排程。
B. java線程間通信有幾種方式
由於線程A和線程B持有同一個MyObject類的對象object,盡管這兩個線程需要調用不同的方法,但是它們是同步執行的,比如:線程B需要等待線程A執行完了methodA()方法之後,它才能執行methodB()方法。這樣,線程A和線程B就實現了 通信。
C. 如何在學習Java過程中實現線程之間的通信
在java中,每個對象都有兩個池,鎖池(monitor)和等待池(waitset),每個對象又都有wait、notify、notifyAll方法,使用它們可以實現線程之間的通信,只是平時用的較少.
wait(): 使當前線程處於等待狀態,直到另外的線程調用notify或notifyAll將它喚醒
notify(): 喚醒該對象監聽的其中一個線程(規則取決於JVM廠商,FILO,FIFO,隨機…)
notifyAll(): 喚醒該對象監聽的所有線程
鎖池: 假設T1線程已經擁有了某個對象(注意:不是類)的鎖,而其它的線程想要調用該對象的synchronized方法(或者synchronized塊),由於這些線程在進入對象的synchronized方法之前都需要先獲得該對象的鎖的擁有權,但是該對象的鎖目前正被T1線程擁有,所以這些線程就進入了該對象的鎖池中.
等待池: 假設T1線程調用了某個對象的wait()方法,T1線程就會釋放該對象的鎖(因為wait()方法必須出現在synchronized中,這樣自然在執行wait()方法之前T1線程就已經擁有了該對象的鎖),同時T1線程進入到了該對象的等待池中.如果有其它線程調用了相同對象的notifyAll()方法,那麼處於該對象的等待池中的線程就會全部進入該對象的鎖池中,從新爭奪鎖的擁有權.如果另外的一個線程調用了相同對象的notify()方法,那麼僅僅有一個處於該對象的等待池中的線程(隨機)會進入該對象的鎖池.
java實現線程間通信的四種方式
1、synchronized同步:這種方式,本質上就是「共享內存」式的通信。多個線程需要訪問同一個共享變數,誰拿到了鎖(獲得了訪問許可權),誰就可以執行。
2、while輪詢:其實就是多線程同時執行,會犧牲部分CPU性能。
3、wait/notify機制
4、管道通信:管道流主要用來實現兩個線程之間的二進制數據的傳播
D. java多線程的同步控制與線程間的通信
按照下面這個運行結果(最後兩行順序不一定):
小張 用 20 元買票
小孫 用 10 元買票
小孫 買到票並拿回 5 元
小趙 用 5 元買票
小趙 買到票並拿回 0 元
小張 買到票並拿回 15 元
public class Main {
public static void main(String[] args) {
try {
TicketSeller ts = new TicketSeller();
// 張某拿著1張20元的人民幣排在第一,孫某拿著1張10元的人民幣排在第二,趙某拿著1張5元的人民幣排在第三。
TicketBuyer zhang = new TicketBuyer(ts, "小張", 20);
Thread tZhang = new Thread(zhang);
tZhang.start();
Thread.sleep(100); // 確保買票順序
TicketBuyer sun = new TicketBuyer(ts, "小孫", 10);
Thread tSun = new Thread(sun);
tSun.start();
Thread.sleep(100);
TicketBuyer zhao = new TicketBuyer(ts, "小趙", 5);
Thread tZhao = new Thread(zhao);
tZhao.start();
} catch (InterruptedException ex) {
}
}
}
class TicketSeller{
//電影票5元一張
private static final int TICKET_PRICE = 5;
private int fiveNumber, tenNumber, twentyNumber;
public TicketSeller(){
//售票員只有1張5元的錢
fiveNumber = 1;
tenNumber = twentyNumber = 0;
}
public synchronized int sellTicket(int receiveMoney){
int changeRequired = receiveMoney - TICKET_PRICE;
while(!prepareChange(changeRequired)){
try {
this.wait();
} catch (InterruptedException ex) {
// Do nothing
}
}
switch(receiveMoney){
case 5: fiveNumber++; break;
case 10: tenNumber++; break;
case 20: twentyNumber++; break;
default: System.out.println("錯誤001");
}
this.notify();
return changeRequired;
}
/**
* 給出找錢
* @param changeRequired 需要找的錢數
* @return 是否能給出
*/
private boolean prepareChange(int changeRequired) {
switch(changeRequired){
case 0:
return true;
case 5:
if(fiveNumber >= 1){
fiveNumber--;
return true;
}
break;
case 10:
// 找一張10元的
if(tenNumber >= 1){
tenNumber--;
return true;
}
// 找兩張5元的
if(fiveNumber >= 2){
fiveNumber-=2;
return true;
}
break;
case 15:
// 找一張10元的+一張5元的
if(tenNumber >= 1 && fiveNumber >= 1){
tenNumber--;
fiveNumber--;
return true;
}
// 找3張5元的
if(fiveNumber >= 3){
fiveNumber-=3;
return true;
}
break;
}
return false;
}
}
class TicketBuyer implements Runnable{
private TicketSeller ts;
private int moneyAvailable;
private String myName;
public TicketBuyer(TicketSeller ts, String name, int moneyAvailable){
this.ts = ts;
this.myName = name;
this.moneyAvailable = moneyAvailable;
}
public void run() {
System.out.printf("%s 用 %d 元買票\r\n", this.myName, this.moneyAvailable);
int change = this.ts.sellTicket(this.moneyAvailable);
System.out.printf("%s 買到票並拿回 %d 元\r\n", this.myName, change);
}
}
E. Java線程之間如何通信
volatile修飾的變數具有可見性。可見性也就是說一旦某個線程修改了該被volatile修飾的變數,它會保證修改的值會立即被更新到主存,當有其他線程需要讀取時,可以立即獲取修改之後的值。在Java中為了加快程序的運行效率,對一些變數的操作通常是在該線程的寄存器或是CPU緩存上進行的,之後才會同步到主存中,而加了volatile修飾符的變數則是直接讀寫主存。
volatile禁止指令重排 ,指令重排是指處理器為了提高程序運行效率,可能會對輸入代碼進行優化,它不保證各個語句的執行順序同代碼中的順序一致,但是它會保證程序最終執行結果和代碼順序執行的結果是一致的。指令重排序不會影響單個線程的執行,但是會影響到線程並發執行的正確性。程序執行到volatile修飾變數的讀操作或者寫操作時,在其前面的操作肯定已經完成,且結果已經對後面的操作可見,在其後面的操作肯定還沒有進行。
synchronized可作用於一段代碼或方法,既可以保證可見性,又能夠保證原子性。可見性體現在:通過synchronized或者Lock能保證同一時刻只有一個線程獲取鎖然後執行同步代碼,並且在釋放鎖之前會將對變數的修改刷新到主存中。
原子性表現在:要麼不執行,要麼執行到底。從而我們可以看出volatile雖然具有可見性但是並不能保證原子性。
性能方面,synchronized關鍵字是防止多個線程同時執行一段代碼,就會影響程序執行效率,而volatile關鍵字在某些情況下性能要優於synchronized。
但是要注意volatile關鍵字是無法替代synchronized關鍵字的,因為volatile關鍵字無法保證操作的原子性。
總結
F. java中怎麼實現線程通信
線程間的相互作用:線程之間需要一些協調通信,來共同完成一件任務。
Object類中相關的方法有兩個notify方法和三個wait方法:
因為wait和notify方法定義在Object類中,因此會被所有的類所繼承。
這些方法都是final的,即它們都是不能被重寫的,不能通過子類覆寫去改變它們的行為。
wait()方法
wait()方法使得當前線程必須要等待,等到另外一個線程調用notify()或者notifyAll()方法。
當前的線程必須擁有當前對象的monitor,也即lock,就是鎖。
線程調用wait()方法,釋放它對鎖的擁有權,然後等待另外的線程來通知它(通知的方式是notify()或者notifyAll()方法),這樣它才能重新獲得鎖的擁有權和恢復執行。
要確保調用wait()方法的時候擁有鎖,即,wait()方法的調用必須放在synchronized方法或synchronized塊中。
G. java線程間通信問題
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadDemo {
/**
* Semaphore 就是大學操作系統裡面講的信號量, 其方法acquire和release分別對應PV操作
* AtomicInteger 是原子變數,對它的操作會轉化為底層的原語(不可分割的操作),這樣多線程並發對其操作就不會有問題,
* 如果是普通的int就還要加鎖才能保證沒問題
*/
public static void main(String[] args) throws InterruptedException {
// 用於啟動另一個線程
Semaphore startThread = new Semaphore(1);
// 用於控制終止程序
AtomicInteger threadCount = new AtomicInteger(0);
for (int i = 1; i <= 10; i++) {
CountThread t = new CountThread("Thread" + i, startThread,
threadCount);
t.start();
}
}
}
class CountThread extends Thread {
// 線程標識
private String label;
// 用於啟動另一個線程
private Semaphore startThread;
// 用於控制終止程序
private AtomicInteger threadCount;
public CountThread(String label, Semaphore startThread,
AtomicInteger threadCount) {
this.label = label;
this.startThread = startThread;
this.threadCount = threadCount;
}
public void run() {
try {
// 等待線程被喚醒
startThread.acquire();
System.out.println("------線程:" + label + " 開始工作------");
} catch (InterruptedException e) {
e.printStackTrace();
}
int num = 0;
while (true) {
System.out.println("線程:" + label + "計數:" + num);
// 計數到5
if (num++ == 5) {
// 喚醒另一個計數線程
startThread.release();
// 10的時候程序終止, incrementAndGet是遞增(也就是++操作), 再取值
if (threadCount.incrementAndGet() == 10) {
System.exit(1);
}
}
}
}
}
研究Java並發,強烈推薦你看《Java並發編程實踐》
H. java的線程之間如何進行消息傳遞
原生Java線程之間只抄能通過共享內存(同一個虛擬機內)來通信。當然你可以通過自己實現,使得線程看起來可以通過消息通信。比如Scala的Actor,可以通過消息傳遞,但Actor本身和線程是有很大不同,不過看起來具備了一些線程功能 。
I. Java中線程間怎麼通訊什麼叫僵死線程
JAVA直接通信 一般有個servicer端 一個client端,servicer啟動後,client與servicer連接,你可以試用UDP協議或者TCP/IP協議在多線程中,線程會sleep,當程序停止時,線程仍然處於sleep中,就出現了僵死線程