本文目錄一覽:
如何使用Java編寫多線程程序(1)
一、簡介1、什麼是線程要說線程,就必須先說說進程,進程就是程序的運行時的一個實例。線程呢可以看作單獨地佔有CPU時間來執行相應的代碼的。對早期的計算機(如DOS)而言,線程既是進程,進程既是進程,因為她是單線程的。當然一個程序可以是多線程的,多線程的各個線程看上去像是並行地獨自完成各自的工作,就像一台一台計算機上運行着多個處理機一樣。在多處理機計算機上實現多線程時,它們確實可以並行工作,而且採用適當的分時策略可以大大提高程序運行的效率。但是二者還是有較大的不同的,線程是共享地址空間的,也就是說多線程可以同時讀取相同的地址空間,並且利用這個空間進行交換數據。 2、為什麼要使用線程為什麼要使用多線程呢?學過《計算機體系結構》的人都知道。將順序執行程序和採用多線程並行執行程序相比,效率是可以大大地提高的。比如,有五個線程thread1, thread2, thread3, thread4, thread5,所耗的CPU時間分別為4,5,1,2,7。(假設CPU輪換周期為4個CPU時間,而且線程之間是彼此獨立的)順序執行需要花費1Array個CPU時間,而並行需要的時間肯定少於1Array個CPU時間,至於具體多少時間要看那些線程是可以同時執行的。這是在非常小規模的情況下,要是面對大規模的進程之間的交互的話,效率可以表現得更高。 3、java中是如何實現多線程的與其他語言不一樣的是,線程的觀念在java是語言中是重要的,根深蒂固的,因為在java語言中的線程系統是java語言自建的, java中有專門的支持多線程的API庫,所以你可以以最快的速度寫一個支持線程的程序。在使用java創建線程的時候,你可以生成一個Thread類或者他的子類對象,並給這個對象發送start()消息(程序可以向任何一個派生自 Runnable 接口的類對象發送 start() 消息的),這樣一來程序會一直執行,直到run返回為止,此時該線程就死掉了。在java語言中,線程有如下特點:§ 在一個程序中而言,主線程的執行位置就是main。而其他線程執行的位置,程序員是可以自定義的。值得注意的是對Applet也是一樣。§ 每個線程執行其代碼的方式都是一次順序執行的。§ 一個線程執行其代碼是與其他線程獨立開來的。如果諸線程之間又相互協作的話,就必須採用一定的交互機制。§ 前面已經說過,線程是共享地址空間的,如果控制不當,這裡很有可能出現死鎖。 各線程之間是相互獨立的,那麼本地變量對一個線程而言就是完全獨立,私有的。所以呢,線程執行時,每個線程都有各自的本地變量拷貝。對象變量(instance variable)在線程之間是可以共享的,這也就是為什麼在java中共享數據對象是如此的好用,但是java線程不能夠武斷地訪問對象變量:他們是需要訪問數據對象的權限的。二、準備知識 在分析這個例子之前,然我們先看看關於線程的幾個概念,上鎖,信號量,和java所提供的API。 上鎖對於大多數的程序而言,他們都需要線程之間相互的通訊來完成整個線程的生命周期,二實現線程之間同步的最簡單的辦法就是上鎖。為了防止相互關聯的兩個線程之間錯誤地訪問共享資源,線程需要在訪問資源的時候上鎖和解鎖,對於鎖而言,有讀鎖,寫鎖和讀寫鎖等不同的同步策略。在java中,所有的對象都有鎖;線程只需要使用synchronized關鍵字就可以獲得鎖。在任一時刻對於給定的類的實例,方法或同步的代碼塊只能被一個線程執行。這是因為代碼在執行之前要求獲得對象的鎖。 信號量通常情況下,多個線程所訪問為數不多的資源,那怎麼控制呢?一個比較非常經典而起非常簡單的辦法就是採用信號量機制。信號量機制的含義就是定義一個信號量,也就是說能夠提供的連接數;當有一個線程佔用了一個連接時,信號量就減一;當一個線程是放了連接時,信號量就加一。
java如何實現信號量集,請注意,是信號量集,而不是信號量,求大神指點
信號量:一個整數;
大於或等於0時代表可供並發進程使用的資源實體數;
小於0時代表正在等待使用臨界區的進程數;
用於互斥的信號量初始值應大於0;
只能通過P、V原語操作而改變;
信號量元素組成:
1、表示信號量元素的值;
2、最後操作信號量元素的進程ID
3、等待信號量元素值+1的進程數;
4、等待信號量元素值為0的進程數;
二、主要函數
1.1 創建信號量
int semget(
key_t key, //標識信號量的關鍵字,有三種方法:1、使用IPC——PRIVATE讓系統產生,
// 2、挑選一個隨機數,3、使用ftok從文件路徑名中產生
int nSemes, //信號量集中元素個數
int flag //IPC_CREAT;IPC_EXCL 只有在信號量集不存在時創建
)
成功:返回信號量句柄
失敗:返回-1
1.2 使用ftok函數根據文件路徑名產生一個關鍵字
key_t ftok(const char *pathname,int proj_id);
路徑名稱必須有相應權限
1.3 控制信號量
int semctl(
int semid, //信號量集的句柄
int semnum, //信號量集的元素數
int cmd, //命令
/*union senum arg */… //
)
成功:返回相應的值
失敗:返回-1
命令詳細說明:
cmd: IPC_RMID 刪除一個信號量
IPC_EXCL 只有在信號量集不存在時創建
IPC_SET 設置信號量的許可權
SETVAL 設置指定信號量的元素的值為 agc.val
GETVAL 獲得一個指定信號量的值
GETPID 獲得最後操縱此元素的最後進程ID
GETNCNT 獲得等待元素變為1的進程數
GETZCNT 獲得等待元素變為0的進程數
用java編寫交通信號燈
按照你的要求編寫的紅綠燈程序,你看看吧,比較簡單。
完整的程序如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Graphics;
public class TrafficLight extends JFrame{
JRadioButton jrbYellow,jrbGreen,jrbRed;
int flag=0;
jpNewPanel jpNewPanel;
public static void main(String[] args){
TrafficLight frame=new TrafficLight();
frame.setSize(500,200);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle(“TrafficLight”);
frame.setVisible(true);
}
public TrafficLight(){
jpNewPanel=new jpNewPanel();
add(jpNewPanel,BorderLayout.CENTER);
JPanel jpRadioButtons=new JPanel();
jpRadioButtons.setLayout(new GridLayout(1,3));
jpRadioButtons.add(jrbYellow=new JRadioButton(“Yellow”));
jpRadioButtons.add(jrbGreen=new JRadioButton(“Green”));
jpRadioButtons.add(jrbRed=new JRadioButton(“Red”));
add(jpRadioButtons,BorderLayout.SOUTH);
ButtonGroup group=new ButtonGroup();
group.add(jrbYellow);
group.add(jrbGreen);
group.add(jrbRed);
jrbYellow.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
flag=2;
jpNewPanel.repaint();
}
});
jrbGreen.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
flag=1;
jpNewPanel.repaint();
}
});
jrbRed.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
flag=3;
jpNewPanel.repaint();
}
});
}
class jpNewPanel extends JPanel{
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawRect(0,0,40,100);
g.drawOval(10,10,20,20);
g.drawOval(10,40,20,20);
g.drawOval(10,70,20,20);
if(flag==1){
g.setColor(Color.GREEN);
g.fillOval(10, 70, 20, 20);
}
else if(flag==2){
g.setColor(Color.YELLOW);
g.fillOval(10, 40, 20, 20);
}
else if(flag==3){
g.setColor(Color.RED);
g.fillOval(10, 10, 20, 20);
}
}
}
}
Semaphore信號量的底層原理
Semaphore(信號量) 是一個線程同步結構,用於在線程間傳遞信號,以避免出現信號丟失(譯者註:下文會具體介紹),或者像鎖一樣用於保護一個關鍵區域。自從5.0開始,jdk在java.util.concurrent包里提供了Semaphore 的官方實現,因此大家不需要自己去實現Semaphore。但是還是很有必要去熟悉如何使用Semaphore及其背後的原理
本文的涉及的主題如下:
一、簡單的Semaphore實現
下面是一個信號量的簡單實現:
查看源代碼打印幫助
Take方法發出一個被存放在Semaphore內部的信號,而Release方法則等待一個信號,當其接收到信號後,標記位signal被清空,然後該方法終止。
使用這個semaphore可以避免錯失某些信號通知。用take方法來代替notify,release方法來代替wait。如果某線程在調用release等待之前調用take方法,那麼調用release方法的線程仍然知道take方法已經被某個線程調用過了,因為該Semaphore內部保存了take方法發出的信號。而wait和notify方法就沒有這樣的功能。
當用semaphore來產生信號時,take和release這兩個方法名看起來有點奇怪。這兩個名字來源於後面把semaphore當做鎖的例子,後面會詳細介紹這個例子,在該例子中,take和release這兩個名字會變得很合理。
二、可計數的Semaphore
上面提到的Semaphore的簡單實現並沒有計算通過調用take方法所產生信號的數量。可以把它改造成具有計數功能的Semaphore。下面是一個可計數的Semaphore的簡單實現。
三、有上限的Semaphore
上面的CountingSemaphore並沒有限制信號的數量。下面的代碼將CountingSemaphore改造成一個信號數量有上限的BoundedSemaphore。
在BoundedSemaphore中,當已經產生的信號數量達到了上限,take方法將阻塞新的信號產生請求,直到某個線程調用release方法後,被阻塞於take方法的線程才能傳遞自己的信號。
原創文章,作者:XTJW,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/142789.html