第一篇:實驗06 線程應(yīng)用及線程并發(fā)庫
實驗六 線程應(yīng)用及線程并發(fā)庫
1.實驗內(nèi)容
實驗題1編寫一程序,實現(xiàn)如下功能:子線程循環(huán)10次,接著主線程循環(huán)100次,接著又回到子線程循環(huán)10次,主線程循環(huán)100次,如此循環(huán)50次。package cn.jp.me;
public class ManageProcedure {
public synchronized void addMainProcedure(){
if(shouldBeSub){ try { wait();
} } for(int i = 1;i <= subTimes;++i){ } shouldBeSub = false;notify();System.out.println(“SubProcedure ” + i);} public synchronized void addSubProcedure(){
if(!shouldBeSub){
try { wait();public ManageProcedure(int subTimes, int mainTimes){
} shouldBeSub = true;this.subTimes = subTimes;this.mainTimes = mainTimes;private boolean shouldBeSub;private int subTimes, mainTimes;} catch(InterruptedException e){
}
} catch(InterruptedException e){
} } } for(int i = 1;i <= mainTimes;++i){ } shouldBeSub = true;notify();System.out.println(“MainProcedure ” + i);package cn.jp.me;
public class SingleProcedure implements Runnable {
@Override public void run(){
if(type.equals(“sub”)){
for(int i = 0;i < times;++i){ } manageProcedure.addSubProcedure();public SingleProcedure(int times, String type,} ManageProcedure manageProcedure){ private int times;private String type;private ManageProcedure manageProcedure;this.times = times;this.type = type;this.manageProcedure = manageProcedure;} else {
for(int i = 0;i < times;++i){ } manageProcedure.addMainProcedure();
} } } package cn.jp.me;
import java.util.Scanner;
public class Text {
} } subThread.start();mainThread.start();Thread subThread = new Thread(subProcedure);Thread mainThread = new Thread(mainProcedure);
ManageProcedure manageProcedure = new ManageProcedure(subTimes, mainTimes);public static void main(String[] args){
int subTimes, mainTimes, totalTimes;Scanner scanner = new Scanner(System.in);System.out.println(“Please Input The SubTimes && MainTimes && The Total Times”);subTimes = scanner.nextInt();mainTimes = scanner.nextInt();totalTimes = scanner.nextInt();SingleProcedure subProcedure = new SingleProcedure(totalTimes, “sub”, manageProcedure);SingleProcedure mainProcedure = new SingleProcedure(totalTimes, “main”, manageProcedure);
實驗題2 設(shè)計4個線程,其中2個線程每次對count增加1,另外兩個線程每次對count減1。
package cn.jp.me;
public class SingleProcedure implements Runnable {
public synchronized void run(){
if(type.equals(“Add”)){ for(int i = 0;i < times;++i){ manageProcedure.add();public SingleProcedure(int runTimes, String typeString,} ManageProcedure manageProcedure){ this.times = runTimes;type = typeString;this.manageProcedure = manageProcedure;private int times;private String type;private ManageProcedure manageProcedure;
}
}
} } for(int i = 0;i < times;++i){ } manageProcedure.substract();} else { package cn.jp.me;public class ManageProcedure {
} package cn.jp.me.text;
import cn.jp.me.ManageProcedure;import cn.jp.jme.SingleProcedure;
public class Text {
Thread addOne = new Thread(singleAdd);public static void main(String[] args){
ManageProcedure manageProcedure = new ManageProcedure();SingleProcedure singleAdd = new SingleProcedure(100 / 2, “Add”, manageProcedure);100 / 2, “substract”, manageProcedure);SingleProcedure singleSubstract = new SingleProcedure(public int getCount(){ } return count;public synchronized void substract(){
}--count;System.out.println(“Thread ” + Thread.currentThread().getName()+ “The Count : ” + getCount());public synchronized void add(){
} ++count;System.out.println(“Thread ” + Thread.currentThread().getName()+ “The Count : ” + getCount());public ManageProcedure(){ } count = 0;private int count;
}
} addOne.setName(“Add One Thread”);Thread addTwo = new Thread(singleAdd);addTwo.setName(“Add Two Thread”);Thread substractOne = new Thread(singleSubstract);substractOne.setName(“Substract One Thread”);Thread substractTwo = new Thread(singleSubstract);substractTwo.setName(“Substract Two Thread”);addOne.start();addTwo.start();substractOne.start();substractTwo.start();
實驗題3 CyclicBarrier是一個同步輔助類,它允許一組線程互相等待,直到到達(dá)某個公共屏障點。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待線程后可以重用,所以稱它為循環(huán)的 barrier。
題目要求:
(1)要在公司大廳集合、然后參觀陳云故居;
(2)參觀完后集合、準(zhǔn)備去淀水湖參觀(有3輛車、對應(yīng)3個線程);
說明:必須等大家都到齊了才能去下個地方、比如說在公司集合、3輛車子都到了才能出發(fā)等。要求:用java線程并發(fā)庫的CyclicBarrier類模擬上述參觀過程。
package cn.jp.me;
import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;
public class SingleProcedure implements Runnable {
@Override public void run(){
System.out.println(“ ” + Thread.currentThread().getName()+ “arrives DaTingn And Start Waitting”);public SingleProcedure(CyclicBarrier barrier){ } this.barrier = barrier;private CyclicBarrier barrier;try { barrier.await();} catch(InterruptedException | BrokenBarrierException e){ } System.out.println(“ ” + Thread.currentThread().getName()e.printStackTrace();
}
}
+ “arrives ChenYunGuJunAnd Start Waitting”);try { barrier.await();} catch(InterruptedException | BrokenBarrierException e){ } e.printStackTrace();package cn.jp.me.text;
import java.util.concurrent.CyclicBarrier;
import cn.jp.me.SingleProcedure;
public class Text {
busOne.start();busTwo.start();busThree.start();
Thread busOne = new Thread(component);busOne.setName(“BusOne”);Thread busTwo = new Thread(component);busTwo.setName(“BusTwo”);Thread busThree = new Thread(component);busThree.setName(“BusThree”);
@Override public void run(){ } System.out.println(“All are arrived and Start to next place”);public static void main(String[] args){ CyclicBarrier barrier = new CyclicBarrier(3, new Runnable(){ });SingleProcedure component = new SingleProcedure(barrier);
} }
實驗題4 某圖書館邀請一著名作家簽名售書,大家去買書,具體情況如下:
(1)買書的讀者很多必須排隊,作家簽好名的書不多(但是他還會看書的銷售的情況,一般滿了10本(假設(shè))就不會再簽了);
(2)有的書還沒有簽名,這樣排在前面的同學(xué)就可以買到書、排在后面的就必須等有了簽過名的書才能買;
(3)已經(jīng)簽好名的書可以放在ArrayBlockingQueue中,簽好名的書不斷的向這個隊列里放,而買書的讀者不斷的從里面取書,如沒有簽名的書,就必須等,書有10本了,作家就停下來休息。買書的每個讀者都可以看作一個線程、作家簽名也可以看作是一個線程;
(4)排在前面的讀者先買。要求:編寫程序,模擬上述過程。
package cn.jp.me;
public class Author implements Runnable {
public Author(CommonData data){ } this.data = data;private CommonData data;
}
package cn.jp.me;
public class Reader implements Runnable {
@Override public void run(){
for(int i = 0;i < data.getTimes();++i){
try { buyABook();} catch(InterruptedException e){ public Reader(CommonData data){ } this.data = data;private CommonData data;private void SignABook()throws InterruptedException {
} while(data.getNumber()== 10){
} data.setSign(data.getSign()+ 1);;System.out.println(“The Author Sign NO.” + data.getSign()+ “ book”);data.put(“The Author Sign No.” + data.getSign()+ “Book”);System.out.println(“There Are ” + data.getNumber()+ “Books Signed”);while(data.getNumber()== 10){
} System.out.println(“There Are 10 Books.The Author Chould Rest A While”);Thread.sleep(4000);System.out.println(“There Are 10 Books.The Author Chould Rest A While”);Thread.sleep(4000);} @Override public void run(){
for(int i = 0;i < data.getTimes();++i){
} try {
} SignABook();e.printStackTrace();} catch(InterruptedException e){
}
}
} } e.printStackTrace();private void buyABook()throws InterruptedException {
} while(data.getNumber()== 0){
} data.setBuy(data.getBuy()+ 1);System.out.println(“Buy The No.” + data.getBuy()+ “ Book”);System.out.println(data.getFirBook()+ “Be Bought”);System.out.println(“There Are ” + data.getNumber()+ “Books Signed”);while(data.getNumber()== 0){
} System.out.println(“There Does Not Exist Books Signed.Must Wait……”);Thread.sleep(3000);System.out.println(“There Does Not Exist Books Signed.Must Wait……”);Thread.sleep(3000);package cn.jp.me;
import java.util.concurrent.ArrayBlockingQueue;
public class CommonData {
public String getFirBook()throws InterruptedException { } return queue.take();public int getNumber(){ } return queue.size();public CommonData(int times){
} queue = new ArrayBlockingQueue
} public void put(String elem)throws InterruptedException { } public int getTimes(){ } public int getBuy(){ } public void setBuy(int buy){ } public int getSign(){ } public void setSign(int sign){ } this.sign = sign;return sign;this.buy = buy;return buy;return times;queue.put(elem);package cn.jp.me;
public class Text {
} public static void main(String[] args){
} CommonData data = new CommonData(100);Author author = new Author(data);Reader reader = new Reader(data);new Thread(author).start();new Thread(reader).start();
實驗題5模擬擁有一定數(shù)量賬戶的銀行,把隨機(jī)產(chǎn)生的錢在不同賬號之間進(jìn)行轉(zhuǎn)移交易。每個賬號都有一個線程,在每筆交易中,都會從線程所服務(wù)的賬戶中隨機(jī)取出一定數(shù)額的錢轉(zhuǎn)移到另一個隨機(jī)賬戶中。
提示: 設(shè)計一個Bank類,它有一個transfer方法,該方法將一定數(shù)額的錢從一個賬戶轉(zhuǎn)移到另一個賬戶,如源賬戶沒有足夠余額,該方法直接返回。
package cn.jp.me;
import java.text.Normalizer.Form;
public class Bank {
}
package cn.jp.me;public int getTotalAccountNum(){ } return totalAccountNum;public void setBalance(int accountNo, int num){ } balance[accountNo] = num;public synchronized void transfer(int from, int to, int amount){
} System.out.println(“The Change From ” + from + “ To ” + to);if(balance[from] >= amount){
} System.out.println();System.out.println(“Before Transfer The Balance Of ” + from + “ : ” + balance[from] + “;Of ” + to + “ : ” + balance[to]);System.out.println(“The Change Amount : ” + amount);balance[from]-= amount;balance[to] += amount;System.out.println(“After Transfer The Balance Of ” + from + “ : ” + balance[from] + “;Of ” + to + “ : ” + balance[to]);public Bank(int accountNum){
} totalAccountNum = accountNum;balance = new int[accountNum + 1];private int totalAccountNum;private int[] balance;} else { System.out.println(“The Account ” + from + “'s Balance Is Not Enough”);
import java.util.Random;
import javax.security.auth.login.AccountException;
public class Account implements Runnable {
} package cn.jp.me;
import java.util.Random;import java.util.Scanner;
public class Text {
} Bank bank = new Bank(accountNum);for(int i = 1;i <= accountNum;++i){
} new Thread(new Account(i, random.nextInt(1000000)+ 0, bank)).start();
System.out.println(“Please Input The Number Of Account You Want To Imitate :”);accountNum = scanner.nextInt();public static void main(String[] args){
Random random = new Random();int accountNum;Scanner scanner = new Scanner(System.in);} bank.transfer(accountNo, to, changeNum);@Override public synchronized void run(){ to = random.nextInt(bank.getTotalAccountNum()+ 1);changeNum = random.nextInt(1000000)+ 0;public Account(int accountNo, int initialValue, Bank bank){
} this.accountNo = accountNo;this.bank = bank;bank.setBalance(accountNo, initialValue);private int accountNo;private Bank bank;private static Random random = new Random();int to, changeNum;}
第二篇:Java線程總結(jié)
Java線程總結(jié)
首先要理解線程首先需要了解一些基本的東西,我們現(xiàn)在所使用的大多數(shù)操作系統(tǒng)都屬于多任務(wù),分時操作系統(tǒng)。正是由于這種操作系統(tǒng)的出現(xiàn)才有了多線程這個概念。我們使用的windows,linux就屬于此列。什么是分時操作系統(tǒng)呢,通俗一點與就是可以同一時間執(zhí)行多個程序的操作系統(tǒng),在自己的電腦上面,你是不是一邊聽歌,一邊聊天還一邊看網(wǎng)頁呢?但實際上,并不上cpu在同時執(zhí)行這些程序,cpu只是將時間切割為時間片,然后將時間片分配給這些程序,獲得時間片的程序開始執(zhí)行,不等執(zhí)行完畢,下個程序又獲得時間片開始執(zhí)行,這樣多個程序輪流執(zhí)行一段時間,由于現(xiàn)在cpu的高速計算能力,給人的感覺就像是多個程序在同時執(zhí)行一樣。
一般可以在同一時間內(nèi)執(zhí)行多個程序的操作系統(tǒng)都有進(jìn)程的概念.一個進(jìn)程就是一個執(zhí)行中的程序,而每一個進(jìn)程都有自己獨立的一塊內(nèi)存空間,一組系統(tǒng)資源.在進(jìn)程概念中,每一個進(jìn)程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨立的.因此可以想像創(chuàng)建并執(zhí)行一個進(jìn)程的系統(tǒng)開像是比較大的,所以線程出現(xiàn)了。在java中,程序通過流控制來執(zhí)行程序流,程序中單個順序的流控制稱為線程,多線程則指的是在單個程序中可以同時運行多個不同的線程,執(zhí)行不同的任務(wù).多線程意味著一個程序的多行語句可以看上去幾乎在同一時間內(nèi)同時運行.(你可以將前面一句話的程序換成進(jìn)程,進(jìn)程是程序的一次執(zhí)行過程,是系統(tǒng)運行程序的基本單位)
線程與進(jìn)程相似,是一段完成某個特定功能的代碼,是程序中單個順序的流控制;但與進(jìn)程不同的是,同類的多個線程是共享一塊內(nèi)存空間和一組系統(tǒng)資源,而線程本身的數(shù)據(jù)通常只有微處理器的寄存器數(shù)據(jù),以及一個供程序執(zhí)行時使用的堆棧.所以系統(tǒng)在產(chǎn)生一個線程,或者在各個線程之間切換時,負(fù)擔(dān)要比進(jìn)程小的多,正因如此,線程也被稱為輕負(fù)荷進(jìn)程(light-weight process).一個進(jìn)程中可以包含多個線程.多任務(wù)是指在一個系統(tǒng)中可以同時運行多個程序,即有多個獨立運行的任務(wù),每個任務(wù)對應(yīng)一個進(jìn)程,同進(jìn)程一樣,一個線程也有從創(chuàng)建,運行到消亡的過程,稱為線程的生命周期.用線程的狀態(tài)(state)表明線程處在生命周期的哪個階段.線程有創(chuàng)建,可運行,運行中,阻塞,死亡五中狀態(tài).通過線程的控制與調(diào)度可使線程在這幾種狀態(tài)間轉(zhuǎn)化每個程序至少自動擁有一個線程,稱為主線程.當(dāng)程序加載到內(nèi)存時,啟動主線程.[線程的運行機(jī)制以及調(diào)度模型]
java中多線程就是一個類或一個程序執(zhí)行或管理多個線程執(zhí)行任務(wù)的能力,每個線程可以獨立于其他線程而獨立運行,當(dāng)然也可以和其他線程協(xié)同運行,一個類控制著它的所有線程,可以決定哪個線程得到優(yōu)先級,哪個線程可以訪問其他類的資源,哪個線程開始執(zhí)行,哪個保持休眠狀態(tài)。下面是線程的機(jī)制圖:
Page 1 of 16
線程的狀態(tài)表示線程正在進(jìn)行的活動以及在此時間段內(nèi)所能完成的任務(wù).線程有創(chuàng)建,可運行,運行中,阻塞,死亡五中狀態(tài).一個具有生命的線程,總是處于這五種狀態(tài)之一: 1.創(chuàng)建狀態(tài)
使用new運算符創(chuàng)建一個線程后,該線程僅僅是一個空對象,系統(tǒng)沒有分配資源,稱該線程處于創(chuàng)建狀態(tài)(new thread)2.可運行狀態(tài)
使用start()方法啟動一個線程后,系統(tǒng)為該線程分配了除CPU外的所需資源,使該線程處于可運行狀態(tài)(Runnable)3.運行中狀態(tài)
Java運行系統(tǒng)通過調(diào)度選中一個Runnable的線程,使其占有CPU并轉(zhuǎn)為運行中狀態(tài)(Running).此時,系統(tǒng)真正執(zhí)行線程的run()方法.4.阻塞狀態(tài)
一個正在運行的線程因某種原因不能繼續(xù)運行時,進(jìn)入阻塞狀態(tài)(Blocked)5.死亡狀態(tài)
線程結(jié)束后是死亡狀態(tài)(Dead)
同一時刻如果有多個線程處于可運行狀態(tài),則他們需要排隊等待CPU資源.此時每個線程自動獲得一個線程的優(yōu)先級(priority),優(yōu)先級的高低反映線程的重要或緊急程度.可運行狀態(tài)的線程按優(yōu)先級排隊,線程調(diào)度依據(jù)優(yōu)先級基礎(chǔ)上的“先到先服務(wù)”原則.線程調(diào)度管理器負(fù)責(zé)線程排隊和CPU在線程間的分配,并由線程調(diào)度算法進(jìn)行調(diào)度.當(dāng)線程調(diào)度管理器選種某個線程時,該線程獲得CPU資源而進(jìn)入運行狀態(tài).線程調(diào)度是先占式調(diào)度,即如果在當(dāng)前線程執(zhí)行過程中一個更高優(yōu)先級的線程進(jìn)入可運行狀態(tài),則這個線程立即被調(diào)度執(zhí)行.先占式調(diào)度分為:獨占式和分時方式.獨占方式下,當(dāng)前執(zhí)行線程將一直執(zhí)行下去,直 到執(zhí)行完畢或由于某種原因主動放棄CPU,或CPU被一個更高優(yōu)先級的線程搶占
分時方式下,當(dāng)前運行線程獲得一個時間片,時間到時,即使沒有執(zhí)行完也要讓出
Page 2 of 16
CPU,進(jìn)入可運行狀態(tài),等待下一個時間片的調(diào)度.系統(tǒng)選中其他可運行狀態(tài)的線程執(zhí)行
分時方式的系統(tǒng)使每個線程工作若干步,實現(xiàn)多線程同時運行
另外請注意下面的線程調(diào)度規(guī)則(如果有不理解,不急,往下看): ①如果兩個或是兩個以上的線程都修改一個對象,那么把執(zhí)行修改的方法定義為被同步的(Synchronized),如果對象更新影響到只讀方法,那么只度方法也應(yīng)該定義為同步的
②如果一個線程必須等待一個對象狀態(tài)發(fā)生變化,那么它應(yīng)該在對象內(nèi)部等待,而不是在外部等待,它可以調(diào)用一個被同步的方法,并讓這個方法調(diào)用wait()③每當(dāng)一個方法改變某個對象的狀態(tài)的時候,它應(yīng)該調(diào)用notifyAll()方法,這給等待隊列的線程提供機(jī)會來看一看執(zhí)行環(huán)境是否已發(fā)生改變
④記住wait(),notify(),notifyAll()方法屬于Object類,而不是Thread類,仔細(xì)檢查看是否每次執(zhí)行wait()方法都有相應(yīng)的notify()或notifyAll()方法,且它們作用與相同的對象 在java中每個類都有一個主線程,要執(zhí)行一個程序,那么這個類當(dāng)中一定要有main方法,這個man方法也就是java class中的主線程。你可以自己創(chuàng)建線程,有兩種方法,一是繼承Thread類,或是實現(xiàn)Runnable接口。一般情況下,最好避免繼承,因為java中是單根繼承,如果你選用繼承,那么你的類就失去了彈性,當(dāng)然也不能全然否定繼承Thread,該方法編寫簡單,可以直接操作線程,適用于單重繼承情況。至于選用那一種,具體情況具體分析。
eg.繼承Thread
public class MyThread_1 extends Thread{ public void run(){ //some code } }
eg.實現(xiàn)Runnable接口
public class MyThread_2 implements Runnable { public void run(){ //some code } }
Page 3 of 16
當(dāng)使用繼承創(chuàng)建線程,這樣啟動線程:
new MyThread_1().start()
當(dāng)使用實現(xiàn)接口創(chuàng)建線程,這樣啟動線程:
new Thread(new MyThread_2()).start()
注意,其實是創(chuàng)建一個線程實例,并以實現(xiàn)了Runnable接口的類為參數(shù)傳入這個實例,當(dāng)執(zhí)行這個線程的時候,MyThread_2中run里面的代碼將被執(zhí)行。下面是完成的例子:
public class MyThread implements Runnable { public void run(){ System.out.println(“My Name is ”+Thread.currentThread().getName());} public static void main(String[] args){ new Thread(new MyThread()).start();} }
執(zhí)行后將打印出: My Name is Thread-0
你也可以創(chuàng)建多個線程,像下面這樣
new Thread(new MyThread()).start();new Thread(new MyThread()).start();new Thread(new MyThread()).start();
那么會打印出:
My Name is Thread-0 My Name is Thread-1
Page 4 of 16
My Name is Thread-2
看了上面的結(jié)果,你可能會認(rèn)為線程的執(zhí)行順序是依次執(zhí)行的,但是那只是一般情況,千萬不要用以為是線程的執(zhí)行機(jī)制;影響線程執(zhí)行順序的因素有幾點:首先看看前面提到的優(yōu)先級別
public class MyThread implements Runnable { public void run(){ System.out.println(“My Name is ”+Thread.currentThread().getName());} public static void main(String[] args){ Thread t1=new Thread(new MyThread());Thread t2=new Thread(new MyThread());Thread t3=new Thread(new MyThread());
t2.setPriority(Thread.MAX_PRIORITY);//賦予最高優(yōu)先級
t1.start();t2.start();t3.start();} }
再看看結(jié)果:
My Name is Thread-1 My Name is Thread-0 My Name is Thread-2
Page 5 of 16
線程的優(yōu)先級分為10級,分別用1到10的整數(shù)代表,默認(rèn)情況是5。上面的t2.setPriority(Thread.MAX_PRIORITY)等價與t2.setPriority(10)
然后是線程程序本身的設(shè)計,比如使用sleep,yield,join,wait等方法(詳情請看JDKDocument)
public class MyThread implements Runnable { public void run(){
try {
int sleepTime =(int)(Math.random()* 100);// 產(chǎn)生隨機(jī)數(shù)字,Thread.currentThread().sleep(sleepTime);// 讓其休眠一定時間,時間又上面sleepTime決定
// public static void sleep(long millis)throw InterruptedException
//(API)
System.out.println(Thread.currentThread().getName()+ “ 睡了 ”
+ sleepTime);
} catch(InterruptedException ie)
// 由于線程在休眠可能被中斷,所以調(diào)用sleep方法的時候需要捕捉異常
Page 6 of 16
{
ie.printStackTrace();
} }
public static void main(String[] args){
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
Thread t3 = new Thread(new MyThread());
t1.start();
t2.start();
t3.start();} }
執(zhí)行后觀察其輸出: Thread-0 睡了 11 Thread-2 睡了 48 Thread-1 睡了 69
上面的執(zhí)行結(jié)果是隨機(jī)的,再執(zhí)行很可能出現(xiàn)不同的結(jié)果。由于上面我在run中添加了休眠語句,當(dāng)線程休眠的時候就會讓出cpu,cpu將會選擇執(zhí)行處于runnable狀態(tài)中的其他線程,當(dāng)然也可能出現(xiàn)這種情況,休眠的Thread立即進(jìn)入了runnable狀態(tài),cpu再次執(zhí)行它。[線程組概念] 線程是可以被組織的,java中存在線程組的概念,每個線程都是一個線程組的成員,線程組把多個線程集成為一個對象,通過線程組可以同時對其中的多個線程進(jìn)行操作,如啟動一個線程組的所有線程等.Java的線程組由java.lang包中的Thread——Group類實現(xiàn).ThreadGroup類用來管理一組線程,包括:線程的數(shù)目,線程間的關(guān)系,線程正在執(zhí)行的操作,以及線程將要啟動或終止時間等.線程組還可以包含線程組.在Java的應(yīng)用程序中,最高層的線程組是名位main的線程組,在main中還可以加入線程或
Page 7 of 16
線程組,在mian的子線程組中也可以加入線程和線程組,形成線程組和線程之間的樹狀繼承關(guān)系。像上面創(chuàng)建的線程都是屬于main這個線程組的。借用上面的例子,main里面可以這樣寫:
public static void main(String[] args){
/***************************************
* ThreadGroup(String name)ThreadGroup(ThreadGroup parent, String name)
***********************************/
ThreadGroup group1 = new ThreadGroup(“group1”);
ThreadGroup group2 = new ThreadGroup(group1, “group2”);
Thread t1 = new Thread(group2, new MyThread());
Thread t2 = new Thread(group2, new MyThread());
Thread t3 = new Thread(group2, new MyThread());
t1.start();
t2.start();
t3.start();} 線程組的嵌套,t1,t2,t3被加入group2,group2加入group1。
Page 8 of 16
另外一個比較多就是關(guān)于線程同步方面的,試想這樣一種情況,你有一筆存款在銀行,你在一家銀行為你的賬戶存款,而你的妻子在另一家銀行從這個賬戶提款,現(xiàn)在你有1000塊在你的賬戶里面。你存入了1000,但是由于另一方也在對這筆存款進(jìn)行操作,人家開始執(zhí)行的時候只看到賬戶里面原來的1000元,當(dāng)你的妻子提款1000元后,你妻子所在的銀行就認(rèn)為你的賬戶里面沒有錢了,而你所在的銀行卻認(rèn)為你還有2000元。看看下面的例子:
class BlankSaving // 儲蓄賬戶 { private static int money = 10000;
public void add(int i){
money = money + i;
System.out.println(“Husband 向銀行存入了 [¥” + i + “]”);}
public void get(int i){
money = money-i;
System.out.println(“Wife 向銀行取走了 [¥” + i + “]”);
if(money < 0)
System.out.println(“余額不足!”);}
Page 9 of 16
public int showMoney(){
return money;} }
class Operater implements Runnable { String name;BlankSaving bs;
public Operater(BlankSaving b, String s){
name = s;
bs = b;
}
public static void oper(String name, BlankSaving bs){
if(name.equals(“husband”)){
try {
for(int i = 0;i < 10;i++){
Page 10 of 16
Thread.currentThread().sleep((int)(Math.random()* 300));
bs.add(1000);
}
} catch(InterruptedException e){
}
} else {
try {
for(int i = 0;i < 10;i++){
Thread.currentThread().sleep((int)(Math.random()* 300));
bs.get(1000);
}
} catch(InterruptedException e){
}
} }
public void run(){
oper(name, bs);}
Page 11 of 16
}
public class BankTest { public static void main(String[] args)throws InterruptedException {
BlankSaving bs = new BlankSaving();
Operater o1 = new Operater(bs, “husband”);
Operater o2 = new Operater(bs, “wife”);
Thread t1 = new Thread(o1);
Thread t2 = new Thread(o2);
t1.start();
t2.start();
Thread.currentThread().sleep(500);} }
下面是其中一次的執(zhí)行結(jié)果:
---------first--------------Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000]
Page 12 of 16
Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Husband 向銀行存入了 [¥1000]
看到了嗎,這可不是正確的需求,在husband還沒有結(jié)束操作的時候,wife就插了進(jìn)來,這樣很可能導(dǎo)致意外的結(jié)果。解決辦法很簡單,就是將對數(shù)據(jù)進(jìn)行操作方法聲明為synchronized,當(dāng)方法被該關(guān)鍵字聲明后,也就意味著,如果這個數(shù)據(jù)被加鎖,只有一個對象得到這個數(shù)據(jù)的鎖的時候該對象才能對這個數(shù)據(jù)進(jìn)行操作。也就是當(dāng)你存款的時候,這筆賬戶在其他地方是不能進(jìn)行操作的,只有你存款完畢,銀行管理人員將賬戶解鎖,其他人才能對這個賬戶進(jìn)行操作。
修改public static void oper(String name,BlankSaving bs)為public static void oper(String name,BlankSaving bs),再看看結(jié)果:
Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Husband 向銀行存入了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000] Wife 向銀行取走了 [¥1000]
當(dāng)丈夫完成操作后,妻子才開始執(zhí)行操作,這樣的話,對共享對象的操作就不會有問題了。
[wait and notify] 你可以利用這兩個方法很好的控制線程的執(zhí)行流程,當(dāng)線程調(diào)用wait方法后,線
Page 13 of 16
程將被掛起,直到被另一線程喚醒(notify)或則是如果wait方法指定有時間得話,在沒有被喚醒的情況下,指定時間時間過后也將自動被喚醒。但是要注意一定,被喚醒并不是指馬上執(zhí)行,而是從組塞狀態(tài)變?yōu)榭蛇\行狀態(tài),其是否運行還要看cpu的調(diào)度。事例代碼:
class MyThread_1 extends Thread {
Object lock;
public MyThread_1(Object o){
lock = o;}
public void run(){
try {
synchronized(lock){
System.out.println(“Enter Thread_1 and wait”);
lock.wait();
System.out.println(“be notified”);
}
} catch(InterruptedException e){
} }
Page 14 of 16
}
class MyThread_2 extends Thread { Object lock;
public MyThread_2(Object o){
lock = o;}
public void run(){
synchronized(lock){
System.out.println(“Enter Thread_2 and notify”);
lock.notify();
} } }
public class MyThread { public static void main(String[] args){
int[] in = new int[0];// notice
MyThread_1 t1 = new MyThread_1(in);
Page 15 of 16
MyThread_2 t2 = new MyThread_2(in);
t1.start();
t2.start();} }
執(zhí)行結(jié)果如下:
Enter Thread_1 and wait Enter Thread_2 and notify Thread_1 be notified
可能你注意到了在使用wait and notify方法得時候我使用了synchronized塊來包裝這兩個方法,這是由于調(diào)用這兩個方法的時候線程必須獲得鎖,也就是上面代碼中的lock[],如果你不用synchronized包裝這兩個方法的得話,又或則鎖不一是同一把,比如在MyThread_2中synchronized(lock)改為synchronized(this),那么執(zhí)行這個程序的時候?qū)伋鰆ava.lang.IllegalMonitorStateException執(zhí)行期異常。另外wait and notify方法是Object中的,并不在Thread這個類中。最后你可能注意到了這點:int[] in=new int[0];為什么不是創(chuàng)建new Object而是一個0長度的數(shù)組,那是因為在java中創(chuàng)建一個0長度的數(shù)組來充當(dāng)鎖更加高效。
Page 16 of 16
第三篇:Java線程編程總結(jié)
線程編程方面
60、java中有幾種方法可以實現(xiàn)一個線程?用什么關(guān)鍵字修飾同步方法? stop()和suspend()方法為何不推薦使用?
答:有兩種實現(xiàn)方法,分別是繼承Thread類與實現(xiàn)Runnable接口 用synchronized關(guān)鍵字修飾同步方法
反對使用stop(),是因為它不安全。它會解除由線程獲取的所有鎖定,而且如果對象處于一種不連貫狀態(tài),那么其他線程能在那種狀態(tài)下檢查和修改它們。結(jié)果很難檢查出真正的問題所在。suspend()方法容易發(fā)生死鎖。調(diào)用suspend()的時候,目標(biāo)線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被“掛起”的線程恢復(fù)運行。對任何線程來說,如果它們想恢復(fù)目標(biāo)線程,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。所以不應(yīng)該使用suspend(),而應(yīng)在自己的Thread類中置入一個標(biāo)志,指出線程應(yīng)該活動還是掛起。若標(biāo)志指出線程應(yīng)該掛起,便用wait()命其進(jìn)入等待狀態(tài)。若標(biāo)志指出線程應(yīng)當(dāng)恢復(fù),則用一個notify()重新啟動線程。61、sleep()和 wait()有什么區(qū)別? 答:sleep是線程類(Thread)的方法,導(dǎo)致此線程暫停執(zhí)行指定時間,給執(zhí)行機(jī)會給其他線程,但是監(jiān)控狀態(tài)依然保持,到時后會自動恢復(fù)。調(diào)用sleep不會釋放對象鎖。
wait是Object類的方法,對此對象調(diào)用wait方法導(dǎo)致本線程放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或notifyAll)后本線程才進(jìn)入對象鎖定池準(zhǔn)備獲得對象鎖進(jìn)入運行狀態(tài)。
62、同步和異步有何異同,在什么情況下分別使用他們?舉例說明。
答:如果數(shù)據(jù)將在線程間共享。例如正在寫的數(shù)據(jù)以后可能被另一個線程讀到,或者正在讀的數(shù)據(jù)可能已經(jīng)被另一個線程寫過了,那么這些數(shù)據(jù)就是共享數(shù)據(jù),必須進(jìn)行同步存取。
當(dāng)應(yīng)用程序在對象上調(diào)用了一個需要花費很長時間來執(zhí)行的方法,并且不希望讓程序等待方法的返回時,就應(yīng)該使用異步編程,在很多情況下采用異步途徑往往更有效率。63、啟動一個線程是用run()還是start()? 答:啟動一個線程是調(diào)用start()方法,使線程所代表的虛擬處理機(jī)處于可運行狀態(tài),這意味著它可以由JVM調(diào)度并執(zhí)行。這并不意味著線程就會立即運行。run()方法可以產(chǎn)生必須退出的標(biāo)志來停止一個線程。
64、當(dāng)一個線程進(jìn)入一個對象的一個synchronized方法后,其它線程是否可進(jìn)入此對象的其它方法? 答:不能,一個對象的一個synchronized方法只能由一個線程訪問。
我認(rèn)為:其他線程可以進(jìn)入非synchronized方法,但不能進(jìn)入這個對象的synchronized方法。65、請說出你所知道的線程同步的方法。
答:wait():使一個線程處于等待狀態(tài),并且釋放所持有的對象的lock。
sleep():使一個正在運行的線程處于睡眠狀態(tài),是一個靜態(tài)方法,調(diào)用此方法要捕捉InterruptedException異常。
notify():喚醒一個處于等待狀態(tài)的線程,注意的是在調(diào)用此方法的時候,并不能確切的喚醒某一個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且不是按優(yōu)先級。
Allnotity():喚醒所有處入等待狀態(tài)的線程,注意并不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。
66、多線程有幾種實現(xiàn)方法,都是什么?同步有幾種實現(xiàn)方法,都是什么? 答:多線程有兩種實現(xiàn)方法,分別是繼承Thread類與實現(xiàn)Runnable接口 同步的實現(xiàn)方面有兩種,分別是synchronized,wait與notify 67、線程的基本概念、線程的基本狀態(tài)以及狀態(tài)之間的關(guān)系
答:線程指在程序執(zhí)行過程中,能夠執(zhí)行程序代碼的一個執(zhí)行單位,每個程序至少都有一個線程,也就是程序本身。
Java中的線程有四種狀態(tài)分別是:運行、就緒、掛起、結(jié)束
68、簡述synchronized和java.util.concurrent.locks.Lock的異同 ? 答:主要相同點:Lock能完成synchronized所實現(xiàn)的所有功能
主要不同點:Lock有比synchronized更精確的線程語義和更好的性能。synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。
Jsp方面
69、forward 和redirect的區(qū)別
答:forward是服務(wù)器請求資源,服務(wù)器直接訪問目標(biāo)地址的URL,把那個URL的響應(yīng)內(nèi)容讀取過來,然后把這些內(nèi)容再發(fā)給瀏覽器,瀏覽器根本不知道服務(wù)器發(fā)送的內(nèi)容是從哪兒來的,所以它的地址欄中還是原來的地址。
redirect就是服務(wù)端根據(jù)邏輯,發(fā)送一個狀態(tài)碼,告訴瀏覽器重新去請求那個地址,一般來說瀏覽器會用剛才請求的所有參數(shù)重新請求,所以session,request參數(shù)都可以獲取。70、jsp有哪些內(nèi)置對象?作用分別是什么?
答:JSP共有以下9種基本內(nèi)置組件(可與ASP的6種內(nèi)部組件相對應(yīng)):
request 用戶端請求,此請求會包含來自GET/POST請求的參數(shù)
response 網(wǎng)頁傳回用戶端的回應(yīng)
pageContext 網(wǎng)頁的屬性是在這里管理
session 與請求有關(guān)的會話期
application servlet 正在執(zhí)行的內(nèi)容
out 用來傳送回應(yīng)的輸出 config servlet的構(gòu)架部件
page JSP網(wǎng)頁本身
exception 針對錯誤網(wǎng)頁,未捕捉的例外
71、jsp有哪些動作?作用分別是什么? 答:JSP共有以下6種基本動作
jsp:include:在頁面被請求的時候引入一個文件。
jsp:useBean:尋找或者實例化一個JavaBean。
jsp:setProperty:設(shè)置JavaBean的屬性。
jsp:getProperty:輸出某個JavaBean的屬性。
jsp:forward:把請求轉(zhuǎn)到一個新的頁面。
jsp:plugin:根據(jù)瀏覽器類型為Java插件生成OBJECT或EMBED標(biāo)記 72、JSP中動態(tài)INCLUDE與靜態(tài)INCLUDE的區(qū)別?
答:動態(tài)INCLUDE用jsp:include動作實現(xiàn)
靜態(tài)INCLUDE用include偽碼實現(xiàn),定不會檢查所含文件的變化,適用于包含靜態(tài)頁面
<%@ include file=“included.htm” %> 73、兩種跳轉(zhuǎn)方式分別是什么?有什么區(qū)別? 答:有兩種,分別為:
74、JSP的內(nèi)置對象及方法。
答:request表示HttpServletRequest對象。它包含了有關(guān)瀏覽器請求的信息,并且提供了幾個用于獲取cookie, header, 和session數(shù)據(jù)的有用的方法。
response表示HttpServletResponse對象,并提供了幾個用于設(shè)置送回 瀏覽器的響應(yīng)的方法(如cookies,頭信息等)
out對象是javax.jsp.JspWriter的一個實例,并提供了幾個方法使你能用于向瀏覽器回送輸出結(jié)果。
pageContext表示一個javax.servlet.jsp.PageContext對象。它是用于方便存取各種范圍的名字空間、servlet相關(guān)的對象的API,并且包裝了通用的servlet相關(guān)功能的方法。
session表示一個請求的javax.servlet.http.HttpSession對象。Session可以存貯用戶的狀態(tài)信息
applicaton 表示一個javax.servle.ServletContext對象。這有助于查找有關(guān)servlet引擎和servlet環(huán)境的信息
config表示一個javax.servlet.ServletConfig對象。該對象用于存取servlet實例的初始化參數(shù)。page表示從該頁面產(chǎn)生的一個servlet實例
Servlet方面
75、說一說Servlet的生命周期?
答:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務(wù)結(jié)束。這個生存期由javax.servlet.Servlet接口的init,service和destroy方法表達(dá)。Servlet被服務(wù)器實例化后,容器運行其init方法,請求到達(dá)時運行其service方法,service方法自動派遣運行與請求對應(yīng)的doXXX方法(doGet,doPost)等,當(dāng)服務(wù)器決定將實例銷毀的時候調(diào)用其destroy方法。
與cgi的區(qū)別在于servlet處于服務(wù)器進(jìn)程中,它通過多線程方式運行其service方法,一個實例可以服務(wù)于多個請求,并且其實例一般不會銷毀,而CGI對每個請求都產(chǎn)生新的進(jìn)程,服務(wù)完成后就銷毀,所以效率上低于servlet。
76、JAVA SERVLET API中forward()與redirect()的區(qū)別?
答:前者僅是容器中控制權(quán)的轉(zhuǎn)向,在客戶端瀏覽器地址欄中不會顯示出轉(zhuǎn)向后的地址;后者則是完全的跳轉(zhuǎn),瀏覽器將會得到跳轉(zhuǎn)的地址,并重新發(fā)送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉(zhuǎn)后的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,盡量使用forward()方法,并且,這樣也有助于隱藏實際的鏈接。在有些情況下,比如,需要跳轉(zhuǎn)到一個其它服務(wù)器上的資源,則必須使用sendRedirect()方法。77、Servlet的基本架構(gòu) 答:
public class ServletName extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { } public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { } }
78、什么情況下調(diào)用doGet()和doPost()?
答:Jsp頁面中的form標(biāo)簽里的method屬性為get時調(diào)用doGet(),為post時調(diào)用doPost()。79、servlet的生命周期
答:web容器加載servlet,生命周期開始。通過調(diào)用servlet的init()方法進(jìn)行servlet的初始化。通過調(diào)用service()方法實現(xiàn),根據(jù)請求的不同調(diào)用不同的do***()方法。結(jié)束服務(wù),web容器調(diào)用servlet的destroy()方法。
80、如何現(xiàn)實servlet的單線程模式 答:<%@ page isThreadSafe=“false”%> 81、頁面間對象傳遞的方法
答:request,session,application,cookie等
82、JSP和Servlet有哪些相同點和不同點,他們之間的聯(lián)系是什么?
答:JSP是Servlet技術(shù)的擴(kuò)展,本質(zhì)上是Servlet的簡易方式,更強(qiáng)調(diào)應(yīng)用的外表表達(dá)。JSP編譯后是“類servlet”。Servlet和JSP最主要的不同點在于,Servlet的應(yīng)用邏輯是在Java文件中,并且完全從表示層中的HTML里分離開來。而JSP的情況是Java和HTML可以組合成一個擴(kuò)展名為.jsp的文件。JSP側(cè)重于視圖,Servlet主要用于控制邏輯。83、四種會話跟蹤技術(shù)
答:會話作用域ServletsJSP 頁面描述
page否是代表與一個頁面相關(guān)的對象和屬性。一個頁面由一個編譯好的 Java servlet 類(可以帶有任何的 include 指令,但是沒有 include 動作)表示。這既包括 servlet 又包括被編譯成 servlet 的 JSP 頁面
request是是代表與 Web 客戶機(jī)發(fā)出的一個請求相關(guān)的對象和屬性。一個請求可能跨越多個頁面,涉及多個 Web 組件(由于 forward 指令和 include 動作的關(guān)系)
session是是代表與用于某個 Web 客戶機(jī)的一個用戶體驗相關(guān)的對象和屬性。一個 Web 會話可以也經(jīng)常會跨越多個客戶機(jī)請求
application是是代表與整個 Web 應(yīng)用程序相關(guān)的對象和屬性。這實質(zhì)上是跨越整個 Web 應(yīng)用程序,包括多個頁面、請求和會話的一個全局作用域 84、Request對象的主要方法 答:
setAttribute(String name,Object):設(shè)置名字為name的request的參數(shù)值 getAttribute(String name):返回由name指定的屬性值
getAttributeNames():返回request對象所有屬性的名字集合,結(jié)果是一個枚舉的實例 getCookies():返回客戶端的所有Cookie對象,結(jié)果是一個Cookie數(shù)組 getCharacterEncoding():返回請求中的字符編碼方式 getContentLength():返回請求的Body的長度
getHeader(String name):獲得HTTP協(xié)議定義的文件頭信息 getHeaders(String name):返回指定名字的request Header的所有值,結(jié)果是一個枚舉的實例 getHeaderNames():返回所以request Header的名字,結(jié)果是一個枚舉的實例 getInputStream():返回請求的輸入流,用于獲得請求中的數(shù)據(jù) getMethod():獲得客戶端向服務(wù)器端傳送數(shù)據(jù)的方法
getParameter(String name):獲得客戶端傳送給服務(wù)器端的有name指定的參數(shù)值
getParameterNames():獲得客戶端傳送給服務(wù)器端的所有參數(shù)的名字,結(jié)果是一個枚舉的實例 getParameterValues(String name):獲得有name指定的參數(shù)的所有值 getProtocol():獲取客戶端向服務(wù)器端傳送數(shù)據(jù)所依據(jù)的協(xié)議名稱 getQueryString():獲得查詢字符串
getRequestURI():獲取發(fā)出請求字符串的客戶端地址 getRemoteAddr():獲取客戶端的IP地址 getRemoteHost():獲取客戶端的名字
getSession([Boolean create]):返回和請求相關(guān)Session getServerName():獲取服務(wù)器的名字
getServletPath():獲取客戶端所請求的腳本文件的路徑 getServerPort():獲取服務(wù)器的端口號
removeAttribute(String name):刪除請求中的一個屬性
85、我們在web應(yīng)用開發(fā)過程中經(jīng)常遇到輸出某種編碼的字符,如iso8859-1等,如何輸出一個某種編碼的字符串? 答:
Public String translate(String str){ String tempStr = “";try { tempStr = new String(str.getBytes(”ISO-8859-1“), ”GBK");tempStr = tempStr.trim();} catch(Exception e){ System.err.println(e.getMessage());} return tempStr;} 86、Servlet執(zhí)行時一般實現(xiàn)哪幾個方法? 答:
public void init(ServletConfig config)public ServletConfig getServletConfig()public String getServletInfo()public void service(ServletRequest request,ServletResponse response)public void destroy()
Jdbc、Jdo方面88、Jdo是什么?
87、Class.forName的作用?為什么要用?
答:調(diào)用該訪問返回一個以字符串指定類名的類的對象。答:JDO是Java對象持久化的新的規(guī)范,為java data object的簡稱,也是一個用于存取某種數(shù)據(jù)倉庫中的對象的標(biāo)準(zhǔn)化API。JDO提供了透明的對象存儲,因此對開發(fā)人員來說,存儲數(shù)據(jù)對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經(jīng)轉(zhuǎn)移到JDO產(chǎn)品提供商身上,使開發(fā)人員解脫出來,從而集中時間和精力在業(yè)務(wù)邏輯上。另外,JDO很靈活,因為它可以在任何數(shù)據(jù)底層上運行。JDBC只是面向關(guān)系數(shù)據(jù)庫(RDBMS)JDO更通用,提供到任何數(shù)據(jù)底層的存儲功能,比如關(guān)系數(shù)據(jù)庫、文件、XML以及對象數(shù)據(jù)庫(ODBMS)等等,使得應(yīng)用可移植性更強(qiáng)。89、說出數(shù)據(jù)連接池的工作機(jī)制是什么? 答:J2EE服務(wù)器啟動時會建立一定數(shù)量的池連接,并一直維持不少于此數(shù)目的池連接。客戶端程序需要連接時,池驅(qū)動程序會返回一個未使用的池連接并將其表記為忙。如果當(dāng)前沒有空閑連接,池驅(qū)動程序就新建一定數(shù)量的連接,新建連接的數(shù)量有配置參數(shù)決定。當(dāng)使用的池連接調(diào)用完成后,池驅(qū)動程序?qū)⒋诉B接表記為空閑,其他調(diào)用就可以使用這個連接。90、Jdo是什么? 答:JDO是Java對象持久化的新的規(guī)范,為java data object的簡稱,也是一個用于存取某種數(shù)據(jù)倉庫中的對象的標(biāo)準(zhǔn)化API。JDO提供了透明的對象存儲,因此對開發(fā)人員來說,存儲數(shù)據(jù)對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經(jīng)轉(zhuǎn)移到JDO產(chǎn)品提供商身上,使開發(fā)人員解脫出來,從而集中時間和精力在業(yè)務(wù)邏輯上。另外,JDO很靈活,因為它可以在任何數(shù)據(jù)底層上運行。JDBC只是面向關(guān)系數(shù)據(jù)庫(RDBMS)JDO更通用,提供到任何數(shù)據(jù)底層的存儲功能,比如關(guān)系數(shù)據(jù)庫、文件、XML以及對象數(shù)據(jù)庫(ODBMS)等等,使得應(yīng)用可移植性更強(qiáng)。
Xml方面
91、xml有哪些解析技術(shù)?區(qū)別是什么? 答:有DOM,SAX,STAX等
DOM:處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結(jié)構(gòu)所造成的,這種結(jié)構(gòu)占用的內(nèi)存較多,而且DOM必須在解析文件之前把整個文檔裝入內(nèi)存,適合對XML的隨機(jī)訪問。
SAX:不現(xiàn)于DOM,SAX是事件驅(qū)動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當(dāng)遇到像文件開頭,文檔結(jié)束,或者標(biāo)簽開頭與標(biāo)簽結(jié)束時,它會觸發(fā)一個事件,用戶通過在其回調(diào)事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問 STAX:Streaming API for XML(StAX)92、你在項目中用到了xml技術(shù)的哪些方面?如何實現(xiàn)的?
答:用到了數(shù)據(jù)存貯,信息配置兩方面。在做數(shù)據(jù)交換平臺時,將不能數(shù)據(jù)源的數(shù)據(jù)組裝成XML文件,然后將XML文件壓縮打包加密后通過網(wǎng)絡(luò)傳送給接收者,接收解密與解壓縮后再同XML文件中還原相關(guān)信息進(jìn)行處理。在做軟件配置時,利用XML可以很方便的進(jìn)行,軟件的各種配置參數(shù)都存貯在XML文件中。
93、XML文檔定義有幾種形式?它們之間有何本質(zhì)區(qū)別?解析XML文檔有哪幾種方式? 答:a: 兩種形式 dtd schema,b: 本質(zhì)區(qū)別:schema本身是xml的,可以被XML解析器解析(這也是從DTD上發(fā)展schema的根本目的),c:有DOM,SAX,STAX等
DOM:處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結(jié)構(gòu)所造成的,這種結(jié)構(gòu)占用的內(nèi)存較多,而且DOM必須在解析文件之前把整個文檔裝入內(nèi)存,適合對XML的隨機(jī)訪問
SAX:不現(xiàn)于DOM,SAX是事件驅(qū)動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當(dāng)遇到像文件開頭,文檔結(jié)束,或者標(biāo)簽開頭與標(biāo)簽結(jié)束時,它會觸發(fā)一個事件,用戶通過在其回調(diào)事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問 STAX:Streaming API for XML(StAX)
第四篇:Weblogic線程堆棧獲取方式小結(jié)
Weblogic線程堆棧獲取方式小結(jié)
當(dāng)服務(wù)器掛起,崩潰或者性能底下時,就需要抓取服務(wù)器的線程堆棧(Thread Dump)用于后續(xù)的分析.Thread dump提供了當(dāng)前活動的線程的快照.它提供了JVM中所有Java線程的棧跟蹤信息,有很多方式可用于獲取Thread Dump, 一些是操作系統(tǒng)特定的命令.操作系統(tǒng)命令獲取ThreadDump: Windows: 轉(zhuǎn)向服務(wù)器的標(biāo)準(zhǔn)輸出窗口并按下Control + Break組合鍵, 之后需要將線程堆棧復(fù)制到文件中
UNIX/ Linux 首先查找到服務(wù)器的進(jìn)程號(process id), 然后獲取堆棧.1.ps –ef | grep java 2.kill-3
注意一定要謹(jǐn)慎, 一步不慎就可能讓服務(wù)器進(jìn)程被殺死!JVM 自帶的工具獲取線程堆棧: JDK自帶命令行工具獲取PID并做ThreadDump: 1.jps 2.jstack
3.使用JVisualVM: Threads 標(biāo)簽頁àThreadDump按鈕.WebLogic 自帶的獲取 thread dump的工具: 1.webLogic.Admin 工具
a.打開命令提示符, 通過運行
b.執(zhí)行下面的命令
java weblogic.Admin-url t3://localhost:7001-username weblogic-password weblogic1 THREAD_DUMP 注意: Thread Dump 會打印到標(biāo)準(zhǔn)輸出, 如nohup日志或者進(jìn)程窗口.2.使用 Admin Console a.登錄 Admin Console , 點擊對應(yīng)的服務(wù)器 b.點擊Server à Monitoring àThreads c.點擊: Dump Thread Stack 按鈕 3.使用WLST(WebLogic Scripting Tool)connect(‘weblogic’,'weblogic1’,’t3://localhost:7001’)cd(‘Servers’)cd(‘AdminServer’)threadDump()disconnect()exit()注意: 線程堆棧將會保存在運行wlst的當(dāng)前目錄下.4.使用utils.ThreadDumper 用法: C:beawlserver_10.3serverlib>java utils.ThreadDumper Broadcast Thread
dumps
disabled:
must
specify
-cp
weblogic.jar weblogic.debug.dumpThreadAddr and weblogic.debug.dumpThreadPort Exception in thread “main” java.lang.IllegalArgumentException: Port out of range :-1 at java.net.DatagramPacket.setPort(Unknown Source)at java.net.DatagramPacket.
第五篇:Java程序員必須掌握的線程知識
Java程序員必須掌握的線程知識 Callable和Future Callable和Future出現(xiàn)的原因
創(chuàng)建線程的2種方式,一種是直接繼承Thread,另外一種就是實現(xiàn)Runnable接口。
這2種方式都有一個缺陷就是:在執(zhí)行完任務(wù)之后無法獲取執(zhí)行結(jié)果。如果需要獲取執(zhí)行結(jié)果,就必須通過共享變量或者使用線程通信的方式來達(dá)到效果,這樣使用起來就比較麻煩。
而自從Java 1.5開始,就提供了Callable和Future,通過它們可以在任務(wù)執(zhí)行完畢之后得到任務(wù)執(zhí)行結(jié)果。
Callable和Future介紹
Callable接口代表一段可以調(diào)用并返回結(jié)果的代碼;Future接口表示異步任務(wù),是還沒有完成的任務(wù)給出的未來結(jié)果。所以說Callable用于產(chǎn)生結(jié)果,F(xiàn)uture用于獲取結(jié)果。
Callable接口使用泛型去定義它的返回類型。Executors類提供了一些有用的方法在線程池中執(zhí)行Callable內(nèi)的任務(wù)。由于Callable任務(wù)是并行的(并行就是整體看上去是并行的,其實在某個時間點只有一個線程在執(zhí)行),我們必須等待它返回的結(jié)果。
java.util.concurrent.Future對象為我們解決了這個問題。在線程池提交Callable任務(wù)后返回了一個Future對象,使用它可以知道Callable任務(wù)的狀態(tài)和得到Callable返回的執(zhí)行結(jié)果。Future提供了get()方法讓我們可以等待Callable結(jié)束并獲取它的執(zhí)行結(jié)果。
Callable與Runnable
java.lang.Runnable吧,它是一個接口,在它里面只聲明了一個run()方法:
publicinterfaceRunnable{
publicabstractvoid run();}
由于run()方法返回值為void類型,所以在執(zhí)行完任務(wù)之后無法返回任何結(jié)果。
Callable位于java.util.concurrent包下,它也是一個接口,在它里面也只聲明了一個方法,只不過這個方法叫做call():
publicinterfaceCallable
/**
* Computes a result, or throws an exception if unable to do so.*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call()throwsException;}
可以看到,這是一個泛型接口,call()函數(shù)返回的類型就是傳遞進(jìn)來的V類型。
那么怎么使用Callable呢?
一般情況下是配合ExecutorService來使用的,在ExecutorService接口中聲明了若干個submit方法的重載版本:
第一個submit方法里面的參數(shù)類型就是Callable。
暫時只需要知道Callable一般是和ExecutorService配合來使用的,具體的使用方法講在后面講述。
一般情況下我們使用第一個submit方法和第三個submit方法,第二個submit方法很少使用。
Future
Future就是對于具體的Runnable或者Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消、查詢是否完成、獲取結(jié)果。必要時可以通過get方法獲取執(zhí)行結(jié)果,該方法會阻塞直到任務(wù)返回結(jié)果。
Future類位于java.util.concurrent包下,它是一個接口:
publicinterfaceFuture
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get()throwsInterruptedException,ExecutionException;
V get(long timeout,TimeUnit unit)
throwsInterruptedException,ExecutionException,TimeoutException;}
在Future接口中聲明了5個方法,下面依次解釋每個方法的作用:
cancel方法用來取消任務(wù),如果取消任務(wù)成功則返回true,如果取消任務(wù)失敗則返回false。參數(shù)mayInterruptIfRunning表示是否允許取消正在執(zhí)行卻沒有執(zhí)行完畢的任務(wù),如果設(shè)置true,則表示可以取消正在執(zhí)行過程中的任務(wù)。如果任務(wù)已經(jīng)完成,則無論mayInterruptIfRunning為true還是false,此方法肯定返回false,即如果取消已經(jīng)完成的任務(wù)會返回false;如果任務(wù)正在執(zhí)行,若mayInterruptIfRunning設(shè)置為true,則返回true,若mayInterruptIfRunning設(shè)置為false,則返回false;如果任務(wù)還沒有執(zhí)行,則無論mayInterruptIfRunning為true還是false,肯定返回true。isCancelled方法表示任務(wù)是否被取消成功,如果在任務(wù)正常完成前被取消成功,則返回 true。
isDone方法表示任務(wù)是否已經(jīng)完成,若任務(wù)完成,則返回true;
get()方法用來獲取執(zhí)行結(jié)果,這個方法會產(chǎn)生阻塞,會一直等到任務(wù)執(zhí)行完畢才返回;
get(long timeout, TimeUnit unit)用來獲取執(zhí)行結(jié)果,如果在指定時間內(nèi),還沒獲取到結(jié)果,就直接返回null。
也就是說Future提供了三種功能:
1)判斷任務(wù)是否完成;
2)能夠中斷任務(wù);
3)能夠獲取任務(wù)執(zhí)行結(jié)果。
因為Future只是一個接口,所以是無法直接用來創(chuàng)建對象使用的,因此就有了下面的FutureTask。FutureTask
FutureTask實現(xiàn)了RunnableFuture接口,這個接口的定義如下:
publicinterfaceRunnableFuture
void run();}
可以看到這個接口實現(xiàn)了Runnable和Future接口,接口中的具體實現(xiàn)由FutureTask來實現(xiàn)。這個類的兩個構(gòu)造方法如下 :
publicFutureTask(Callable
if(callable ==null)
thrownewNullPointerException();
sync =newSync(callable);
}
publicFutureTask(Runnable runnable, V result){
sync =newSync(Executors.callable(runnable, result));
} 如上提供了兩個構(gòu)造函數(shù),一個以Callable為參數(shù),另外一個以Runnable為參數(shù)。這些類之間的關(guān)聯(lián)對于任務(wù)建模的辦法非常靈活,允許你基于FutureTask的Runnable特性(因為它實現(xiàn)了Runnable接口),把任務(wù)寫成Callable,然后封裝進(jìn)一個由執(zhí)行者調(diào)度并在必要時可以取消的FutureTask。
FutureTask可以由執(zhí)行者調(diào)度,這一點很關(guān)鍵。它對外提供的方法基本上就是Future和Runnable接口的組合:get()、cancel、isDone()、isCancelled()和run(),而run()方法通常都是由執(zhí)行者調(diào)用,我們基本上不需要直接調(diào)用它。
一個FutureTask的例子
publicclassMyCallableimplementsCallable
privatelong waitTime;
publicMyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
@Override
publicString call()throwsException{ Thread.sleep(waitTime);
//return the thread name executing this callable task
returnThread.currentThread().getName();
}
}
publicclassFutureTaskExample{
publicstaticvoid main(String[] args){
MyCallable callable1 =newMyCallable(1000);// 要執(zhí)行的任務(wù)
MyCallable callable2 =newMyCallable(2000);
FutureTask
FutureTask
ExecutorService executor =Executors.newFixedThreadPool(2);// 創(chuàng)建線程池并返回ExecutorService實例
executor.execute(futureTask1);// 執(zhí)行任務(wù)
executor.execute(futureTask2);
while(true){
try{
if(futureTask1.isDone()&& futureTask2.isDone()){// 兩個任務(wù)都完成System.out.println(“Done”);
executor.shutdown();// 關(guān)閉線程池和服務(wù)
return;
}
if(!futureTask1.isDone()){// 任務(wù)1沒有完成,會等待,直到任務(wù)完成 System.out.println(“FutureTask1 output=”+futureTask1.get());
}
System.out.println(“Waiting for FutureTask2 to complete”);
String s = futureTask2.get(200L,TimeUnit.MILLISECONDS);
if(s!=null){
System.out.println(“FutureTask2 output=”+s);
}
}catch(InterruptedException|ExecutionException e){
e.printStackTrace();
}catch(TimeoutException e){
//do nothing
}
} }}
運行如上程序后,可以看到一段時間內(nèi)沒有輸出,因為get()方法等待任務(wù)執(zhí)行完成然后才輸出內(nèi)容.輸出結(jié)果如下:
FutureTask1 output=pool-1-thread-1WaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeFutureTask2 output=pool-1-thread-2Done