筆試題目一:請(qǐng)編寫一個(gè)多線程程序,實(shí)現(xiàn)兩個(gè)線程其中一個(gè)線程完成對(duì)某個(gè)對(duì)象的int成員變量的增加操作即每次加1,另一個(gè)線程完成對(duì)該對(duì)象的成員變量的減操作,即每次減1,同時(shí)要保證該變量的值不會(huì)小于0猿诸,不會(huì)大于1,該變量的初始值為0
答案狡忙,具體代碼如下:
package com.test;
//被操縱的對(duì)象
public class Sample2 {
private int v;
public synchronized void increase() {
if (v != 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
v++;
System.out.println(v);
notify();
}
public synchronized void decrease() {
if (v != 1) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
v--;
System.out.println(v);
notify();
}
}
package com.test;
//減線程操縱Sample2對(duì)象的decrease方法
public class IncreaseThread extends Thread {
Sample2 sample;
public IncreaseThread(Sample2 sample) {
this.sample = sample;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
sample.increase();
}
}
}
package com.test;
//增加線程操縱Sample2對(duì)象的increase方法
public class DecreaseThread extends Thread {
Sample2 sample;
public DecreaseThread(Sample2 sample) {
this.sample = sample;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
sample.decrease();
}
}
}
package com.test;
//程序的入口
public class Main {
public static void main(String[] args) {
Sample2 sample = new Sample2();
Thread increaseThread = new IncreaseThread(sample);
Thread decreaseThread = new DecreaseThread(sample);
increaseThread.start();
decreaseThread.start();
}
}
解題思路:首先這是一題關(guān)于線程之間通信的題目,典型的生產(chǎn)者與消費(fèi)者問(wèn)題,涉及到線程通信就需要用到wait方法以及notify方法或者notifyAll方法
筆試題目二:關(guān)于wait梳虽、notify、notifyAll以及sleep方法的關(guān)系(重點(diǎn))
- 如果一個(gè)線程調(diào)用了某個(gè)對(duì)象的wait方法灾茁,那么該線程首先必須擁有該對(duì)象的鎖(換句話說(shuō),一個(gè)線程如果調(diào)用了某個(gè)對(duì)象的wait方法,那么該wait方法必須要在synchronized中)
- 如果一個(gè)線程調(diào)用了某個(gè)對(duì)象的wait方法,那么該線程完全釋放該對(duì)象的鎖
- 在java對(duì)象中有兩種池(鎖池窜觉、等待池)
- 如果一個(gè)線程用了某個(gè)對(duì)象的wait方法,那么該線程進(jìn)入該對(duì)象的等待池中(釋放鎖)是复,如果未來(lái)的某一時(shí)刻,另外一個(gè)線程調(diào)用了相同對(duì)象的notify后者notifyAll方法竖螃,那么在該等待池中的等待的線程就會(huì)起來(lái)進(jìn)入該對(duì)象的鎖池中等待獲得該對(duì)象的鎖,如果獲得鎖成功后淑廊,那么該線程將繼續(xù)沿著wait方法之后的路徑去執(zhí)行。(也就是說(shuō)從等待池中被喚醒的線程并不會(huì)馬上獲得對(duì)象的鎖特咆,而是要先進(jìn)入到鎖池中,與其他鎖池中的線程一并去爭(zhēng)搶對(duì)象的鎖)
筆試題目三:wait(long timeout)的特點(diǎn)是什么?
答案:1. 等待timeout時(shí)間后自己起來(lái) 2. 在等待時(shí)間內(nèi)被通知?jiǎng)t起來(lái)
筆試題目四: Thread.sleep與wait區(qū)別是什么?
答案:如果一個(gè)線程調(diào)用了sleep方法睡眠,那么在睡眠的同時(shí)它不會(huì)失去對(duì)象的鎖的擁有權(quán),而wait方法線程會(huì)釋放掉對(duì)象的鎖并及進(jìn)入到對(duì)象的等待池中季惩。
學(xué)習(xí)線程的時(shí)候遇到的困惑一:一個(gè)線程循環(huán)調(diào)用了某個(gè)對(duì)象的同步方法那么循環(huán)一次就會(huì)釋放鎖一次?還是說(shuō)從循環(huán)開始到循環(huán)結(jié)束之前一直占據(jù)鎖直到循環(huán)結(jié)束才釋放腻格?
經(jīng)過(guò)代碼測(cè)試:循環(huán)一次就會(huì)釋放一次鎖画拾,重新調(diào)用對(duì)象的同步方法的時(shí)候會(huì)去判斷是否該對(duì)象加了鎖。即重新調(diào)用對(duì)象同步方法的時(shí)候會(huì)與其他線程進(jìn)行搶鎖
學(xué)習(xí)線程的時(shí)候遇到的困惑二:一個(gè)線程循環(huán)調(diào)用了某個(gè)對(duì)象的同步方法菜职,假設(shè)循環(huán)第一次的時(shí)候就執(zhí)行到了wait方法,我們都知道wait方法會(huì)讓線程釋放掉對(duì)象的鎖青抛,并進(jìn)入到對(duì)象的等待池中,那么第二次循環(huán)會(huì)開始嗎酬核?
答:第二次循環(huán)暫時(shí)不會(huì)開始蜜另,只有當(dāng)次的循環(huán)結(jié)束后才會(huì)開始,也就是說(shuō)循環(huán)執(zhí)行到wait方法后該線程被掛起了(線程阻塞了)嫡意,暫時(shí)不能繼續(xù)往下執(zhí)行了举瑰,直到其它線程把它喚醒,它才有機(jī)會(huì)執(zhí)行完當(dāng)次循環(huán)所調(diào)用的同步方法蔬螟,只有完整地執(zhí)行完第一次循環(huán)所調(diào)用的同步方法后才能進(jìn)行第二次循環(huán)此迅。
關(guān)于線程的知識(shí)點(diǎn)補(bǔ)充:
- 在某個(gè)對(duì)象的所有synchronized方法中,在某一時(shí)刻只能有一個(gè)線程正在訪問(wèn)其中的一個(gè)synchronized方法旧巾,其他線程都在鎖池中等待
- 如果一個(gè)方法是synchronized方法耸序,那么該synchronized關(guān)鍵字表示給當(dāng)前對(duì)象上鎖(即this)
- 如果一個(gè)synchronized方法是靜態(tài)的(static的)那么該synchronized關(guān)鍵字表示給當(dāng)前對(duì)象所對(duì)應(yīng)的class對(duì)象上鎖(每個(gè)類,不管生成多少個(gè)對(duì)象鲁猩,其對(duì)立的class對(duì)象只有一個(gè))