大家在學(xué)習(xí)java的時(shí)候,一定遇到過Object類,因?yàn)樵趈ava單一繼承體系中Object類是根類,所有的類都會(huì)繼承它,并擁有Object的公共方法,意味著在java的面向?qū)ο蟮氖澜缰校袑?duì)象都擁有這些方法,非常通用。那么我們來看一看這些方法有哪些?
直接看一下,Object類的源碼:
package java.lang;
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class《?》 getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout 《 0) {
throw new IllegalArgumentException(“timeout value is negative”);
}
if (nanos 《 0 || nanos 》 999999) {
throw new IllegalArgumentException(
“nanosecond timeout value out of range”);
}
if (nanos 》= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
其實(shí)看JDK文檔大家都能知道這些方法的含義,不過我把自己對(duì)它們的理解介紹一下,這里面public的方法,重點(diǎn)我會(huì)詳細(xì)介紹較難掌握的wait和notify方法。
具體方法的說明如下:
public String toString()
這個(gè)默認(rèn)是打印對(duì)象的getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
類名@哈希碼,可子類可重寫該方法定義自己的對(duì)象字符串,最常用。
public final native Class《?》 getClass();
獲取對(duì)象的類名,在反射中可以用到。
public int hashCode();
public boolean equals(Object obj)
這兩個(gè)方法在集合框架的Set集合類中用途非常重要,因?yàn)镾et集合中的元素不允許重復(fù),各種自定義對(duì)象如何判斷是否重復(fù),就是通過重寫這兩個(gè)方法來完成的。
public final native void notify();
public final native void notifyAll();
public final void wait()
public final native void wait(long timeout)
public final void wait(long timeout, int nanos)
這里幾組方法有多個(gè)重載方法,不過核心的方法就是wait方法和notify方法,這兩個(gè)方法,如果沒有學(xué)習(xí)過java多線程編程估計(jì)不會(huì)接觸到,這涉及到線程的同步以及在同步條件下線程通信的問題。
java 線程同步機(jī)制就是保證多個(gè)線程訪問同一個(gè)共享對(duì)象時(shí)不發(fā)生沖突的步驟是上鎖、操作、釋放鎖。而這個(gè)鎖是在java對(duì)象中隱含的鎖,鎖也叫“同步監(jiān)視器” ,它是所有對(duì)象都擁有的,你不用可視而不見,
其實(shí)就定義在Object類中,不過我們不用了解它的存在,為了防止同一個(gè)共享對(duì)象不發(fā)生沖突,java用 synchronized 來保護(hù)共享對(duì)象不處于競(jìng)爭(zhēng)狀態(tài)。,可采用同步方法或同步塊來完成,但是當(dāng)同步環(huán)境下兩個(gè)線程需要通信怎么辦?如果沒有通信機(jī)制,兩個(gè)線程只能針對(duì)鎖的獲取發(fā)出輪詢效率很低,這里Object類的wait和notify兩個(gè)方法就可以解決這個(gè)問題。
采用 wait()/notify() 實(shí)現(xiàn)同步條件下線程間通信的原理如下:
使用前提:必須是同步條件,否則調(diào)用會(huì)異常。
調(diào)用wait()
調(diào)用線程會(huì)放棄CPU
調(diào)用線程釋放鎖
調(diào)用線程進(jìn)入鎖的等待集合(池),等待CPU重新調(diào)度。
調(diào)用notify()
某個(gè)線程從鎖的等待集合中離開進(jìn)入準(zhǔn)備運(yùn)行狀態(tài)
被通知的線程必須重新請(qǐng)求鎖才能執(zhí)行。
notify()不能精確指定被通知的線程。
notifyAll() 通知所有在等待集合的線程離開進(jìn)入準(zhǔn)備運(yùn)行狀態(tài)
下面以經(jīng)典的生產(chǎn)者和消費(fèi)者問題來了解生產(chǎn)者線程Producer和消費(fèi)者線程Consumer,同步一個(gè)同享對(duì)象Shop,利用wait和notify方法來通信的代碼:
Puducer.java 生產(chǎn)者線程定義
public class Producer implements Runnable{
Shop shop;
public Producer(Shop shop) {
// TODO Auto-generated constructor stub
this.shop=shop;
new Thread(this,“生產(chǎn)者線程”).start();
}
@Override
public void run() {
// TODO Auto-generated method stub
int i=0;
while(true){
shop.put(i++);
}
}
}
Consumer.java 消費(fèi)者線程定義
public class Consumer implements Runnable{
Shop shop;
public Consumer(Shop shop) {
// TODO Auto-generated constructor stub
this.shop=shop;
new Thread(this,“消費(fèi)者線程”).start();
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
shop.get();
}
}
}
共享對(duì)象Shop.java定義
public class Shop {
int no;
boolean hasData=false; //false表示無數(shù)據(jù) true有數(shù)據(jù)
synchronized int get(){ //消費(fèi)產(chǎn)品
if(hasData==false){
try {
wait();//消費(fèi)者線程暫停
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(“消費(fèi):”+no);
hasData=false;//消費(fèi)完了。通知生產(chǎn)
notify();
return no;
}
synchronized void put(int no){ //放產(chǎn)品
if(hasData==true){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(“生產(chǎn):”+no);
hasData=true;
this.no=no;
notify();
}
}
測(cè)試類PC.java
public class PC {
public static void main(String[] args) {
Shop shop=new Shop();
new Producer(shop);
new Consumer(shop);
}
}
以上生產(chǎn)消費(fèi)者問題很好的說明了wait和notify方法的用途,其他方法的變種例如wait(long timeout)就好理解了,如果超過指定時(shí)間等待的線程也會(huì)進(jìn)入等待集合而不用再等待。
責(zé)任編輯:ct
評(píng)論
查看更多