導航:首頁 > 編程語言 > java線程通訊

java線程通訊

發布時間:2024-10-23 23:40:32

❶ 如何在學習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、管道通信:管道流主要用來實現兩個線程之間的二進制數據的傳播

❷ java阻塞隊列 線程同步合作

Queue介面與List Set同一級別 都是繼承了Collection介面 LinkedList實現了Queue介面 Queue介面窄化了對LinkedList的方法的訪問許可權(即在方法中的參數類型如果是Queue時 就完全只能訪問Queue介面所定義的方法了 而不能直接訪問 LinkedList的非Queue的方法) 以使得只有恰當的方法才可以使用 BlockingQueue 繼承了Queue介面

隊列是一種數據結構.它有兩個基本操作 在隊列尾部加人一個元素 和從隊列頭部移除一個元素就是說 隊列以一種先進先出的方式管理數據 如果你試圖向一個已經滿了的阻塞隊列中添加一個元素或者是從一個空的阻塞隊列中移除一個元索 將導致線程阻塞.在多線程進行合作時 阻塞隊列是很有用的工具 工作者線程可以定期地把中間結果存到阻塞隊列中而其他工作者線線程把中間結果取出並在將來修改它們 隊列會自動平衡負載 如果第一個線程集運行得比第二個慢 則第二個線程集在等待結果時就會阻塞 如果第一個線程集運行得快 那麼它將等待第二個線程集趕上來 下表顯示了jdk 中的阻塞隊列的操作

add 增加一個元索 如果隊列已春慎橋滿 則拋出一個IIIegaISlabEepeplian異常

remove 移除並返回隊列頭部的元素 如果隊列為空 則拋出一個NoSuchElementException異常

element 返回隊列頭部的元素 如果隊列為空 則拋出一個NoSuchElementException異常

offer 添加一個元素並返回true 如果隊列已滿 則返回false

poll 移除並返問隊列頭部的元素 如果隊列扒猛為空 則返回null

peek 返回隊列頭部的元素 如果隊列為空 則返回null

put 添加一個元素 如果隊列滿 則阻塞

take 移除並返回隊列頭部的元素 如果隊列為空 則阻塞

remove element offer poll peek 其實是屬於Queue介面

阻塞隊列的操作可以根據它們的響應方式分為以下三類 aad removee和element操作在你試圖為一個已滿的隊列增加元素或從空隊列取得元素時拋出異常 當然 在多線程程序中 隊列在任何時間都可能變成滿的或空的 所以你可能想使用offer poll peek方法 這些方法在無法完成任務時只是給出一個出錯示而不會拋出異常

注意 poll和peek方法出錯進返回null 因此 向隊列中插入null值是不合法的

還有帶超時的offer和poll方法變種 例如 下面的調用

boolean success = q offer(x TimeUnit MILLISECONDS);

嘗試在 毫秒內向隊列尾部插入一個元素 如果成功 立即返回true 否則 當到達超時進 返回false 同樣地 調用

Object head = q poll( TimeUnit MILLISECONDS);

如果在 毫秒內成功地移除了隊列頭元素 則立即返回頭元素 否則在到達超時時 返回null

最後 我們有阻塞操作put和take put方法在隊列滿時阻塞 take方法在隊列空時阻塞

ncurrent包提供了阻塞隊列的 個變種 默認情況下 LinkedBlockingQueue的容量是沒有上限的(說的不準確 在不指定時容量為Integer MAX_VALUE 不要然的話在put時怎麼會受阻呢) 但是也可以選擇指定其最大容量 它是基孝仔於鏈表的隊列 此隊列按 FIFO(先進先出)排序元素

ArrayBlockingQueue在構造時需要指定容量 並可以選擇是否需要公平性 如果公平參數被設置true 等待時間最長的線程會優先得到處理(其實就是通過將ReentrantLock設置為true來達到這種公平性的 即等待時間最長的線程會先操作) 通常 公平性會使你在性能上付出代價 只有在的確非常需要的時候再使用它 它是基於數組的阻塞循環隊列 此隊列按 FIFO(先進先出)原則對元素進行排序

PriorityBlockingQueue是一個帶優先順序的隊列 而不是先進先出隊列 元素按優先順序順序被移除 該隊列也沒有上限(看了一下源碼 PriorityBlockingQueue是對PriorityQueue的再次包裝 是基於堆數據結構的 而PriorityQueue是沒有容量限制的 與ArrayList一樣 所以在優先阻塞隊列上put時是不會受阻的 雖然此隊列邏輯上是無界的 但是由於資源被耗盡 所以試圖執行添加操作可能會導致 OutOfMemoryError) 但是如果隊列為空 那麼取元素的操作take就會阻塞 所以它的檢索操作take是受阻的 另外 往入該隊列中的元素要具有比較能力

最後 DelayQueue(基於PriorityQueue來實現的)是一個存放Delayed 元素的無界阻塞隊列 只有在延遲期滿時才能從中提取元素 該隊列的頭部是延遲期滿後保存時間最長的 Delayed 元素 如果延遲都還沒有期滿 則隊列沒有頭部 並且poll將返回null 當一個元素的 getDelay(TimeUnit NANOSECONDS) 方法返回一個小於或等於零的值時 則出現期滿 poll就以移除這個元素了 此隊列不允許使用 null 元素 下面是延遲介面

Java代碼

public interface Delayed extends Comparable<Delayed> {

long getDelay(TimeUnit unit);

}

public interface Delayed extends Comparable<Delayed> {

long getDelay(TimeUnit unit);

}

放入DelayQueue的元素還將要實現pareTo方法 DelayQueue使用這個來為元素排序

下面的實例展示了如何使用阻塞隊列來控制線程集 程序在一個目錄及它的所有子目錄下搜索所有文件 列印出包含指定關鍵字的文件列表 從下面實例可以看出 使用阻塞隊列兩個顯著的好處就是 多線程操作共同的隊列時不需要額外的同步 另外就是隊列會自動平衡負載 即那邊(生產與消費兩邊)處理快了就會被阻塞掉 從而減少兩邊的處理速度差距 下面是具體實現

Java代碼

public class BlockingQueueTest {

public static void main(String[] args) {

Scanner in = new Scanner(System in);

System out print( Enter base directory (e g /usr/local/jdk /src): );

String directory = in nextLine();

System out print( Enter keyword (e g volatile): );

String keyword = in nextLine();

final int FILE_QUEUE_SIZE = ;// 阻塞隊列大小

final int SEARCH_THREADS = ;// 關鍵字搜索線程個數

// 基於ArrayBlockingQueue的阻塞隊列

BlockingQueue<File> queue = new ArrayBlockingQueue<File>(

FILE_QUEUE_SIZE);

//只啟動一個線程來搜索目錄

FileEnumerationTask enumerator = new FileEnumerationTask(queue

new File(directory));

new Thread(enumerator) start();

//啟動 個線程用來在文件中搜索指定的關鍵字

for (int i = ; i <= SEARCH_THREADS; i++)

new Thread(new SearchTask(queue keyword)) start();

}

}

class FileEnumerationTask implements Runnable {

//啞元文件對象 放在阻塞隊列最後 用來標示文件已被遍歷完

public static File DUMMY = new File( );

private BlockingQueue<File> queue;

private File startingDirectory;

public FileEnumerationTask(BlockingQueue<File> queue File startingDirectory) {

this queue = queue;

this startingDirectory = startingDirectory;

}

public void run() {

try {

enumerate(startingDirectory);

queue put(DUMMY);//執行到這里說明指定的目錄下文件已被遍歷完

} catch (InterruptedException e) {

}

}

// 將指定目錄下的所有文件以File對象的形式放入阻塞隊列中

public void enumerate(File directory) throws InterruptedException {

File[] files = directory listFiles();

for (File file : files) {

if (file isDirectory())

enumerate(file);

else

//將元素放入隊尾 如果隊列滿 則阻塞

queue put(file);

}

}

}

class SearchTask implements Runnable {

private BlockingQueue<File> queue;

private String keyword;

public SearchTask(BlockingQueue<File> queue String keyword) {

this queue = queue;

this keyword = keyword;

}

public void run() {

try {

boolean done = false;

while (!done) {

//取出隊首元素 如果隊列為空 則阻塞

File file = queue take();

if (file == FileEnumerationTask DUMMY) {

//取出來後重新放入 好讓其他線程讀到它時也很快的結束

queue put(file);

done = true;

} else

search(file);

}

} catch (IOException e) {

e printStackTrace();

} catch (InterruptedException e) {

}

}

public void search(File file) throws IOException {

Scanner in = new Scanner(new FileInputStream(file));

int lineNumber = ;

while (in hasNextLine()) {

lineNumber++;

String line = in nextLine();

if (ntains(keyword))

System out printf( %s:%d:%s%n file getPath() lineNumber

line);

}

in close();

}

lishixin/Article/program/Java/hx/201311/26657

❸ Java中線程間怎麼通訊什麼叫僵死線程

JAVA直接通信 一般有個servicer端 一個client端,servicer啟動後,client與servicer連接,你可以試用UDP協議或者TCP/IP協議在多線程中,線程會sleep,當程序停止時,線程仍然處於sleep中,就出現了僵死線程

❹ java 進程間通訊的有幾種方法

進程間通信的方法主要有以下幾種:

(1)管道(Pipe):管道可用於具有親緣關系進程間的通信,允許一個進程和另一個與它有共同祖先的進程之間進行通信。
(2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關 系進程間的通信。命名管道在文件系統中有對應的文件名。命名管道通過命令mkfifo或系統調用mkfifo來創建。
(3)信號(Signal):信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送 信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD為了實現可靠信號機制,又能夠統一對外介面,用sigaction函數重新實現了signal函數)。
(4)消息(Message)隊列:消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠許可權的進程可以向隊列中添加消息,被賦予讀許可權的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式位元組流以及緩沖區大小受限等缺
(5)共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
(6)內存映射(mapped memory):內存映射允許任何多個進程間通信,每一個使用該機制的進程通過把一個共享的文件映射到自己的進程地址空間來實現它。
(7)信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。
(8)套介面(Socket):更為一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字。

而在java中我們實現多線程間通信則主要採用"共享變數"和"管道流"這兩種方法

方法一 通過訪問共享變數的方式(注:需要處理同步問題)
方法二 通過管道流

其中方法一有兩種實現方法,即
方法一a)通過內部類實現線程的共享變數
代碼如下:

public class Innersharethread {
public static void main(String[] args) {
Mythread mythread = new Mythread();
mythread.getThread().start();
mythread.getThread().start();
mythread.getThread().start();
mythread.getThread().start();
}
}
class Mythread {
int index = 0;
private class InnerThread extends Thread {
public synchronized void run() {
while (true) {
System.out.println(Thread.currentThread().getName()
+ "is running and index is " + index++);
}
}
}
public Thread getThread() {
return new InnerThread();
}
}
/**
* 通過內部類實現線程的共享變數
*
*/
public class Innersharethread {
public static void main(String[] args) {
Mythread mythread = new Mythread();
mythread.getThread().start();
mythread.getThread().start();
mythread.getThread().start();
mythread.getThread().start();
}
}
class Mythread {
int index = 0;
private class InnerThread extends Thread {
public synchronized void run() {
while (true) {
System.out.println(Thread.currentThread().getName()
+ "is running and index is " + index++);
}
}
}
public Thread getThread() {
return new InnerThread();
}
}

b)通過實現Runnable介面實現線程的共享變數
代碼如下:

public class Interfacaesharethread {
public static void main(String[] args) {
Mythread mythread = new Mythread();
new Thread(mythread).start();
new Thread(mythread).start();
new Thread(mythread).start();
new Thread(mythread).start();
}
}
/* 實現Runnable介面 */
class Mythread implements Runnable {
int index = 0;
public synchronized void run() {
while (true)
System.out.println(Thread.currentThread().getName() + "is running and
the index is " + index++);
}
}
/**
* 通過實現Runnable介面實現線程的共享變數
*/
public class Interfacaesharethread {
public static void main(String[] args) {
Mythread mythread = new Mythread();
new Thread(mythread).start();
new Thread(mythread).start();
new Thread(mythread).start();
new Thread(mythread).start();
}
}
/* 實現Runnable介面 */
class Mythread implements Runnable {
int index = 0;
public synchronized void run() {
while (true)
System.out.println(Thread.currentThread().getName() + "is running and
the index is " + index++);
}
}

方法二(通過管道流):
代碼如下:

public class CommunicateWhitPiping {
public static void main(String[] args) {
/**
* 創建管道輸出流
*/
PipedOutputStream pos = new PipedOutputStream();
/**
* 創建管道輸入流
*/
PipedInputStream pis = new PipedInputStream();
try {
/**
* 將管道輸入流與輸出流連接 此過程也可通過重載的構造函數來實現
*/
pos.connect(pis);
} catch (IOException e) {
e.printStackTrace();
}
/**
* 創建生產者線程
*/
Procer p = new Procer(pos);
/**
* 創建消費者線程
*/
Consumer c = new Consumer(pis);
/**
* 啟動線程
*/
p.start();
c.start();
}
}
/**
* 生產者線程(與一個管道輸入流相關聯)
*
*/
class Procer extends Thread {
private PipedOutputStream pos;
public Procer(PipedOutputStream pos) {
this.pos = pos;
}
public void run() {
int i = 8;
try {
pos.write(i);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 消費者線程(與一個管道輸入流相關聯)
*
*/
class Consumer extends Thread {
private PipedInputStream pis;
public Consumer(PipedInputStream pis) {
this.pis = pis;
}
public void run() {
try {
System.out.println(pis.read());
} catch (IOException e) {
e.printStackTrace();
}
}
}

❺ java中同步有幾種方式啊

1。同步代碼塊:
synchronized(同一個數據){} 同一個數據:就是N條線程同時訪問一個數據。
2。
同步方法:
public synchronized 數據返回類型 方法名(){}

是使用 synchronized 來修飾某個方法,則該方法稱為同步方法。對於同步方法而言,無需顯示指定同步監視器,同步方法的同步監視器是
this
也就是該對象的本身(這里指的對象本身有點含糊,其實就是調用該同步方法的對象)通過使用同步方法,可非常方便的將某類變成線程安全的類,具有如下特徵:
1,該類的對象可以被多個線程安全的訪問。
2,每個線程調用該對象的任意方法之後,都將得到正確的結果。
3,每個線程調用該對象的任意方法之後,該對象狀態依然保持合理狀態。
註:synchronized關鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構造器,屬性等。
實現同步機制注意以下幾點: 安全性高,性能低,在多線程用。性能高,安全性低,在單線程用。
1,不要對線程安全類的所有方法都進行同步,只對那些會改變共享資源方法的進行同步。
2,如果可變類有兩種運行環境,當線程環境和多線程環境則應該為該可變類提供兩種版本:線程安全版本和線程不安全版本(沒有同步方法和同步塊)。在單線程中環境中,使用線程不安全版本以保證性能,在多線程中使用線程安全版本.

線程通訊:
為什麼要使用線程通訊?

使用synchronized
來修飾某個共享資源時(分同步代碼塊和同步方法兩種情況),當某個線程獲得共享資源的鎖後就可以執行相應的代碼段,直到該線程運行完該代碼段後才釋放對該

共享資源的鎖,讓其他線程有機會執行對該共享資源的修改。當某個線程佔有某個共享資源的鎖時,如果另外一個線程也想獲得這把鎖運行就需要使用wait()
和notify()/notifyAll()方法來進行線程通訊了。
Java.lang.object 里的三個方法wait() notify() notifyAll()
wait方法導致當前線程等待,直到其他線程調用同步監視器的notify方法或notifyAll方法來喚醒該線程。
wait(mills)方法
都是等待指定時間後自動蘇醒,調用wait方法的當前線程會釋放該同步監視器的鎖定,可以不用notify或notifyAll方法把它喚醒。
notify()
喚醒在同步監視器上等待的單個線程,如果所有線程都在同步監視器上等待,則會選擇喚醒其中一個線程,選擇是任意性的,只有當前線程放棄對該同步監視器的鎖定後,也就是使用wait方法後,才可以執行被喚醒的線程。
notifyAll()方法
喚醒在同步監視器上等待的所有的線程。只用當前線程放棄對該同步監視器的鎖定後,才可以執行被喚醒的線程

❻ java 高並發 都有哪些技術

我用的JAVA NIO,一般常用的高並發IO框架,也是用的這個做擴展。

Java NIO是在jdk1.4開始使用的,它既可以說成「新I/O」,也可以說成非阻塞式I/O。下面是java NIO的工作原理:

1. 由一個專門的線程來處理所有的 IO 事件,並負責分發。
2. 事件驅動機制:事件到的時候觸發,而不是同步的去監視事件。
3. 線程通訊:線程之間通過 wait,notify 等方式通訊。保證每次上下文切換都是有意義的。減少無謂的線程切換。

Java NIO的服務端只需啟動一個專門的線程來處理所有的 IO 事件,這種通信模型是怎麼實現的呢?呵呵,我們一起來探究它的奧秘吧。java NIO採用了雙向通道(channel)進行數據傳輸,而不是單向的流(stream),在通道上可以注冊我們感興趣的事件。一共有以下四種事件:

事件名 對應值
服務端接收客戶端連接事件 SelectionKey.OP_ACCEPT(16)
客戶端連接服務端事件 SelectionKey.OP_CONNECT(8)
讀事件 SelectionKey.OP_READ(1)
寫事件 SelectionKey.OP_WRITE(4)

服務端和客戶端各自維護一個管理通道的對象,我們稱之為selector,該對象能檢測一個或多個通道 (channel) 上的事件。我們以服務端為例,如果服務端的selector上注冊了讀事件,某時刻客戶端給服務端發送了一些數據,阻塞I/O這時會調用read()方法阻塞地讀取數據,而NIO的服務端會在selector中添加一個讀事件。服務端的處理線程會輪詢地訪問selector,如果訪問selector時發現有感興趣的事件到達,則處理這些事件,如果沒有感興趣的事件到達,則處理線程會一直阻塞直到感興趣的事件到達為止。下面是我理解的java NIO的通信模型示意圖:

❼ 在用java開發程序中什麼時候應用到線程

一般 需要獨立運行某個東西的時候會用到線程
我用過的就是 埠監聽的時候
比如說 你的程序在200埠上 設置另一個監聽,當有數據通過這個埠傳輸的時候 就會被監聽程序所獲取 但是如何保證 實時監聽?這個就需要有個線程獨立的 來執行這個工作 保持監聽的狀態。

再比如說 你需要做一個任務處理的程序 當資料庫中有新任務時候就進行處理/或者XX路徑下出現新的文件 就進行處理,這個時候 也需要用到線程 來實時掃描資料庫或者是文件路徑,來保證任務能夠得到及時的處理

閱讀全文

與java線程通訊相關的資料

熱點內容
為什麼燕窩溯源碼可以更改經銷商 瀏覽:949
和伺服器連接的交換機叫什麼 瀏覽:773
蘋果手機如何設置伺服器 瀏覽:934
迅雷下載游戲需要解壓 瀏覽:853
3d平滑命令 瀏覽:41
必須去車管所解壓 瀏覽:387
室友命令我 瀏覽:311
lol全部命令 瀏覽:40
用什麼APP查指數 瀏覽:921
什麼是作品源碼 瀏覽:671
我的理想程序員該怎麼寫 瀏覽:842
英譯中國現代散文選pdf 瀏覽:448
裝飾設計模式java 瀏覽:23
linuxshell清屏命令 瀏覽:136
惠利app是什麼 瀏覽:779
游戲埠讀取伺服器失敗怎麼弄 瀏覽:878
linux修復mbr 瀏覽:128
磁碟格式化基本命令 瀏覽:578
程序員掉入異世界 瀏覽:954
andlua畫質助手源碼 瀏覽:577