程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> 如何使用Java編寫多線程程序

如何使用Java編寫多線程程序

編輯:JAVA編程入門知識

一、簡介

1、什麼是線程

要說線程,就必須先說說進程,進程就是程序的運行時的一個實例。線程呢可以看作單獨地占有CPU時間來執行相應的代碼的。對早期的計算機(如DOS)而言,線程既是進程,進程既是進程,因為她是單線程的。當然一個程序可以是多線程的,多線程的各個線程看上去像是並行地獨自完成各自的工作,就像一台一台計算機上運行著多個處理機一樣。在多處理機計算機上實現多線程時,它們確實可以並行工作,而且采用適當的分時策略可以大大提高程序運行的效率。但是二者還是有較大的不同的,線程是共享地址空間的,也就是說多線程可以同時讀取相同的地址空間,並且利用這個空間進行交換數據。

2、為什麼要使用線程

為什麼要使用多線程呢?學過《計算機體系結構》的人都知道。將順序執行程序和采用多線程並行執行程序相比,效率是可以大大地提高的。比如,有五個線程thread1, thread2, thread3, thread4, thread5,所耗的CPU時間分別為4,5,1,2,7。(假設CPU輪換周期為4個CPU時間,而且線程之間是彼此獨立的)順序執行需要花費19個CPU時間,而並行需要的時間肯定少於19個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關鍵字就可以獲得鎖。在任一時刻對於給定的類的實例,方法或同步的代碼塊只能被一個線程執行。這是因為代碼在執行之前要求獲得對象的鎖。

信號量

通常情況下,多個線程所訪問為數不多的資源,那怎麼控制呢?一個比較非常經典而起非常簡單的辦法就是采用信號量機制。信號量機制的含義就是定義一個信號量,也就是說能夠提供的連接數;當有一個線程占用了一個連接時,信號量就減一;當一個線程是放了連接時,信號量就加一。采用這種方法就可以簡單有效地控制線程的同步問題,而且實現起來也特別方便。看下面的代碼:

class Semaphore {

private int count;

public Semaphore(int count) {

this.count = count;

}

public synchronized void acquire() {

while(count == 0) {

try {

wait();

} catch (InterruptedException e) {

//keep trying

}

}

count--;

}

public synchronized void release() {

count++;

notify(); //alert a thread that′s blocking on this semaphore

}

}

java中提供了哪些api以編寫多線程程序

這裡只列出幾個常用的方法和屬性值。

屬性值,有三個MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY

方法:

Thread(); //建立一個線程

void run(); //對於一個繼承了Runnable接口的class而言,

//他運行一個線程,否著他什麼都不做

void setPriority(int newPriority); //設置優先級

void start(); //運行一個程序

void sleep(long millis); //線程睡眠millis毫秒

static void yield(); //臨時pause一個程序以便起他線程運行

三、程序示例

例一、

讓我們看看下面的例子。取錢的流程是輸入密碼,然後確定要取得金額,如果所取的金額小於或等於可以取出的金額,WITHDRAW則返回TRUE,然後ATM機出錢,然後打印清單;否則返回FALSE,然後打印清單。如下圖:

public class AutomatedTellerMachine extends Teller {

public void withdraw(float amount) {

Account a = getAccount();

if (a.deduct(amount))

dispense(amount);

printReceipt();

}

}

public class Account {

private float total;

public boolean deduct(float t) {

if (t <= total) {

total -= t;

return true;

}

return false;

}

}

就這個例子而言,假設有這種情況,對同一個賬號可以在不同的地方取錢,在同一時間,不同地點,妻子和丈夫取錢,妻子輸入了賬號上的最大金額,丈夫也是一樣,假如妻子輸入後已經得到true的返回值,但是丈夫的線程所得到的值還沒有更新,這樣丈夫也能夠得到true的返回值,這樣就出現了問題!這個問題怎麼解決呢?在java裡面提供了控制機制以保證deduct操作時的原子性,那就是關鍵字synchronized。

在Account的deduct方法加入synchronized就可以解決這個問題。

例二、

在這裡我們用多線程中最典型的例子,生產者與消費者問題。在這個例子裡面我們定義了生產者Producer,消費者Consumer和倉庫Warehouse三個類,在整個程序的生命周期裡,生產者隨機地制造出產品放到倉庫中,消費者也是隨即地從倉庫中取出產品。

import exception.ProducerConsumerException;

/**

* Consumer.j

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved