Objcet類知識整合

Object類位于java.lang包中,java.lang包有最基礎(chǔ)的和核心的類,在編譯時(shí)會自動導(dǎo)入;

Object類是所有java類的祖先,每個(gè)類都使用Object作為超類,所有對象(數(shù)組)都實(shí)現(xiàn)這個(gè)類的方法.可以使用類型為Objcet的變量指向任意類型的對象

1.clone方法

保護(hù)方法,實(shí)現(xiàn)對象的淺復(fù)制宅荤,只有實(shí)現(xiàn)了Cloneable接口才可以調(diào)用該方法殖侵,否則拋出CloneNotSupportedException異常。

主要是JAVA里除了8種基本類型傳參數(shù)是值傳遞奏司,其他的類對象傳參數(shù)都是引用傳遞,我們有時(shí)候不希望在方法里講參數(shù)改變樟插,這是就需要在類中復(fù)寫clone方法韵洋。

直接調(diào)用Object的clone()方法來copy一個(gè)副本竿刁,但是發(fā)現(xiàn)myEclipse的提示中并沒有該方法,以為在jdk1.7中取消了該方法搪缨,然后我直接敲上clone()后:

[java]?view plain?copy

public?class?TestObject?{??

public?static?void?main(String[]?args)?{??

Student?s?=new?Student(1,?"小時(shí)");??

s.clone();//報(bào)錯(cuò)??

????}??

}??

編譯報(bào)錯(cuò):The method clone() from the type Object is not visible

后來看了看源碼食拜,發(fā)現(xiàn)原來是這樣:

Object源碼中對于clone()方法的描述:

[java]?view plain?copy

protected?native?Object?clone()?throws?CloneNotSupportedException;??

native修飾詞解析:native的方法就是一個(gè)java調(diào)用非java代碼的接口,是一個(gè)其他語言實(shí)現(xiàn)的方法副编。

問題1:Object類是所有?類的父類,那么為什么子類不能訪問父類的protected修飾的方法呢?

以前對protected的理解是錯(cuò)誤的负甸,protected的方法在自己的包中與public相同

在不同包,指的是通過自身實(shí)例(自身的引用)訪問,而不能通過父類實(shí)例(引用)訪問

所以上端代碼中調(diào)用Student類的clone()方法會包編譯錯(cuò)誤,下面的代碼(通過自身引用調(diào))就OK的

[java]?view plain?copy

public?class?TestObject?{??

public?static?void?main(String[]?args)?{??

TestBoject?t?=new?TestObject();??

t.clone();//ok??

????}??

}??

問題2:要想實(shí)現(xiàn)類似文章開頭的代碼功能該怎么辦痹届?

在Object的源碼中注釋到:

首先呻待,如果這個(gè)類沒有實(shí)現(xiàn)Cloneable這個(gè)接口,將會拋出CloneNotSupportedException队腐,但是所有的數(shù)組都被看成實(shí)現(xiàn)了這個(gè)接口蚕捉。此方法執(zhí)行的是該對象的“淺表復(fù)制”,而不“深層復(fù)制”操作香到。

Object 類本身不實(shí)現(xiàn)接口 Cloneable鱼冀,所以在類為 Object 的對象上調(diào)用 clone 方法將會導(dǎo)致在運(yùn)行時(shí)拋出異常。

在Cloneable的源碼中注釋到:

此類實(shí)現(xiàn)了 Cloneable 接口悠就,以指示 Object.clone() 方法可以合法地對該類實(shí)例進(jìn)行按字段復(fù)制千绪。 如果在沒有實(shí)現(xiàn) Cloneable 接口的實(shí)例上調(diào)用 Object 的 clone 方法,則會導(dǎo)致拋出 CloneNotSupportedException異常梗脾。?

按照慣例荸型,實(shí)現(xiàn)此接口的類應(yīng)該使用公共方法重寫 Object.clone(它是受保護(hù)的)。請參閱 Object.clone()炸茧,以獲得有關(guān)重寫此方法的詳細(xì)信息瑞妇。?

注意,此接口不包含 clone 方法梭冠。因此辕狰,因?yàn)槟硞€(gè)對象實(shí)現(xiàn)了此接口就克隆它是不可能的。即使 clone 方法是反射性調(diào)用的控漠,也無法保證它將獲得成功

解讀:Cloneable接口沒有任何方法蔓倍,僅是個(gè)標(biāo)志接口(tagging interface),若要具有克隆能力盐捷,實(shí)現(xiàn)Cloneable接口的類必須重寫從Object繼承來的clone方法偶翅,并調(diào)用Object的clone方法(見下面Object#clone的定義),重寫后的方法應(yīng)為public 的碉渡。For example(標(biāo)準(zhǔn)寫法):

示例代碼:

[java]?view plain?copy

public?class?TestObject?{??

public?static?void?main(String[]?args)?{??

Student?s?=new?Student(1,?"小時(shí)");??

????????System.out.println(s.clone().getClass());??

????????System.out.println(s.clone().equals(s));??

????}??

}??


class?Student?implements?Cloneable{??

public?int?id;??

public?String?name;??


Student(int?id,?String?name){??

this.id?=?id;??

this.name?=?name;??

????}??


public?Object?clone(){??

Student?s?=null;??

try{??

s?=?(Student)super.clone();??

}catch(CloneNotSupportedException?e){??

????????????????e.printStackTrace();??

????????????}??

return?s;???

????}??

}??

2.getClass方法

final方法聚谁,獲得運(yùn)行時(shí)類型。

一滞诺、

getClass方法:

類型:public final Class getClass()

功能:返回該對象的運(yùn)行時(shí)類的java.lang.Class對象(API上的解釋)

有方法類型可以知道形导,該方法只能由類的實(shí)例變量調(diào)用

例子:

[java]view plaincopy

JButton?b1?=?new?JButton("button1");??

System.out.println(b1.getClass());??

輸出:

class javax.swing.JButton

class屬性

當(dāng)你要獲得一個(gè)類的Class對象時(shí)(作函數(shù)參數(shù)的時(shí)候)环疼,你不能調(diào)用getClass方法,那你只能用類名.class來達(dá)到效果

例子:

[java]view plaincopy

System.out.println(JButton.class);??

輸出:

class javax.swing.JButton

getName方法:

類型:public String getName()

功能:以String形式返回次Class對象所表示的實(shí)體名稱

例子:

[java]view plaincopy

JButton?b1?=?new?JButton("button1");??

System.out.println(b1.getName());??

輸出:

javax.swing.JButton

可以發(fā)現(xiàn)用class屬性和getClass返回的輸出是一樣的朵耕,用getName返回的比前面兩種少了class和一個(gè)空格秦爆。

?.eclipse工具 可以按"."然后馬上提示很多方法 供你選擇

那他如何知道"."了以后有哪些方法?

他用的語法就是getClass().getMethods();


二、

.class其實(shí)是在java運(yùn)行時(shí)就加載進(jìn)去的

getClass()是運(yùn)行程序時(shí)動態(tài)加載的

下面以例子說明:

首先建一個(gè)基類Baseclass??


packageclassyongfa;


publicclassBaseclass?{


privateString?height;

publicString?getHeight(){??

returnheight;

}??


publicvoidsetHeight(String?height){??


this.height=height;


}??

下面是繼承Baseclass類Extendclass??


packageclassyongfa;


publicclassExtendclassextendsBaseclass?{


privateString?width;

publicString?getWidth(){??

returnwidth;

}??


publicvoidsetWidth(String?width){??


this.width=width;


}??

publicstaticvoidmain(String[]?arg0){??

Baseclass?baseclass1=newExtendclass();

Baseclass?baseclass2=newBaseclass();

System.out.println(baseclass1.getClass().getSimpleName());//實(shí)際運(yùn)行的是繼承類Extendclass

System.out.println(baseclass2.getClass().getSimpleName());//實(shí)際運(yùn)行的是Baseclass

System.out.println(Baseclass.class.getSimpleName());//加載時(shí)類名

System.out.println(Extendclass.class.getSimpleName());//加載時(shí)類名

}??


結(jié)果是??


Extendclass??

Baseclass??

Baseclass??

Extendclass


三憔披、四種獲取Class對象的方法 Java反射機(jī)制

下面以一個(gè)具體的實(shí)例來說明。此實(shí)例來自《精通Hibernate 3.0 Java數(shù)據(jù)庫持久層開發(fā)實(shí)踐》一書爸吮。

先在com.hqh.reflect下建一個(gè)文件UseInfojava

package com.hqh.reflect;

public classUseInfo{

private Integer id;

private String userName;

private String password;

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

}

package com.hqh.reflect;

public classGetClassTest{

public static void main(String[] args) {

GetClassTest test = new GetClassTest();

if(test.ClassCheck())

System.out.println("OK");

}

public boolean ClassCheck() {

try {

System.out.println("通過類本身獲得對象");

Class userClass =this.getClass();

System.out.println(userClass.getName());

System.out.println("===========");

System.out.println("通過子類的實(shí)例獲得父類對象");

UseInfo useInfo = new UseInfo();

userClass = useInfo.getClass();

System.out.println(userClass.getName());

Class subUserClass = userClass.getSuperclass();

System.out.println(subUserClass.getName());

System.out.println("===========");

System.out.println("通過類名.class獲取對象");

Class forClass =com.hqh.reflect.UseInfo.class;

System.out.println(forClass.getName());

System.out.println("===========");

System.out.println("通過類名的字符串獲取對象");

Class forName =Class.forName("com.hqh.reflect.UseInfo");

System.out.println(forName.getName());

System.out.println("=============");

} catch (Exception e) {

e.printStackTrace();

return false;

}

return true;

}

}

結(jié)果:

通過類本身獲得對象

com.hqh.reflect.GetClassTest

===========

通過子類的實(shí)例獲得父類對象

com.hqh.reflect.UseInfo

java.lang.Object

===========

通過類名.class獲取對象

com.hqh.reflect.UseInfo

===========

通過類名的字符串獲取對象

com.hqh.reflect.UseInfo

=============

3.toString方法

返回該對象的字符串表示芬膝。通常,toString方法會返回一個(gè)“以文本方式表示”此對象的字符串形娇。結(jié)果應(yīng)是一個(gè)簡明但易于讀懂的信息表達(dá)式锰霜。建議所有子類都重寫此方法。

Object類的toString方法返回一個(gè)字符串桐早,該字符串由類名(對象是該類的一個(gè)實(shí)例)癣缅、at 標(biāo)記符“@”和此對象哈希碼的無符號十六進(jìn)制表示組成。換句話說哄酝,該方法返回一個(gè)字符串友存,它的值等于:

getClass().getName() + '@' + Integer.toHexString(hashCode())

返回:

該對象的字符串表示形式。

因?yàn)樗荗bject里面已經(jīng)有了的方法陶衅,而所有類都是繼承Object屡立,所以“所有對象都有這個(gè)方法”。

它通常只是為了方便輸出搀军,比如System.out.println(xx)膨俐,括號里面的“xx”如果不是String類型的話,就自動調(diào)用xx的toString()方法

總而言之罩句,它只是sun公司開發(fā)java的時(shí)候?yàn)榱朔奖闼蓄惖淖址僮鞫匾饧尤氲囊粋€(gè)方法

寫這個(gè)方法的用途就是為了方便操作焚刺,所以在文件操作里面可用可不用


例子1:

publicclassOrc{

public static class A {

public String toString() {

return"this is A";

}

}

public static void main(String[] args) {

????????A obj = newA( );

????????System.out.println(obj);

}

}

如果某個(gè)方法里面有如下句子:?

A obj=new A();

System.out.println(obj);

會得到輸出:this is A


例子2:

public class Orc{

public static class A {

public String getString() {

return"this is A";? ? ? ? ? ? ?

}? ? ?

}

public static void main(String[] args)? {? ? ?

? ? ? ? A obj =newA();? ? ? ? ? ? ?

? ? ? ? ?System. out. println(obj);? ? ? ? ? ? ?

? ? ? ? ?System. out. println(obj.getString());? ? ?

}

}

會得到輸出:xxxx@xxxxxxx的類名加地址形式

System.out.println(obj.getString());

會得到輸出:this is A


看出區(qū)別了嗎,toString的好處是在碰到“println”之類的輸出方法時(shí)會自動調(diào)用门烂,不用顯式打出來乳愉。

public class Zhang {

public static void main(String[] args) {?

? ? ?StringBuffer MyStrBuff1 =newStringBuffer();? ? ? ??

? ? ?MyStrBuff1.append("Hello,Guys!");

? ? ?System.out.println(MyStrBuff1.toString());

? ? ?MyStrBuff1.insert(6, 30);

? ? System.out.println(MyStrBuff1.toString());??

}

}


值得注意的是,?若希望將StringBuffer在屏幕上顯示出來,?則必須首先調(diào)用toString方法把它變成字符串常量,因?yàn)镻rintStream的方法println()不接受StringBuffer類型的參數(shù).

public class Zhang{

public static void main(String[] args){

????String MyStr =new StringBuffer();?

? ? MyStr =new? StringBuffer().append(MyStr).append(" Guys!").toString();

? ? System.out.println(MyStr);?

?}

}

toString()方法在此的作用是將StringBuffer類型轉(zhuǎn)換為String類型.

public class Zhang{

public static void main(String[] args){

? ? ?String MyStr =new StringBuffer().append("hello").toString();

? ? ?MyStr =new StringBuffer().append(MyStr).append(" Guys!").toString();

? ? ?System.out.println(MyStr);

}}

1.toString()方法

Object類具有一個(gè)toString()方法,你創(chuàng)建的每個(gè)類都會繼承該方法诅福。它返回對象的一個(gè)String表示匾委,并且對于調(diào)試非常有幫助。然而對于默認(rèn)的toString()方法往往不能滿足需求氓润,需要覆蓋這個(gè)方法赂乐。

toString()方法將對象轉(zhuǎn)換為字符串】看以下代碼:

package sample;

class Villain {

????private String name;

????protected void set(String nm) {

???????name = nm;

????}

????public Villain(String name) {

???????this.name = name;

????}

????public String toString() {

???????return "I'm a Villain and my name is " + name;

????}

}

public class Orc extends Villain {

????private int orcNumber;

????public Orc(String name, int orcNumber) {

???????super(name);

???????this.orcNumber = orcNumber;

????}

????public void change(String name, int orcNumber) {

???????set(name);

???????this.orcNumber = orcNumber;

????}

????public String toString() {

???????return "Orc" + orcNumber + ":" + super.toString();

????}

????public static void main(String[] args) {

???????Orc orc = new Orc("Limburger", 12);

???????System.out.println(orc);

???????orc.change("Bob", 19);

???????System.out.println(orc);

????}

}

結(jié)果:

sample.Orc@11b86e7

sample.Orc@11b86e7

如果去掉注釋挨措,即加入2個(gè)toString()方法后挖滤,得到

結(jié)果:

Orc12:I'm a Villain and my name is Limburger

Orc19:I'm a Villain and my name is Bob

2.在容器類中使用toString()

編寫一個(gè)工具類,用于在控制臺輸出Iterator浅役。

import java.util.Iterator;

public class Printer {

????static void printAll(Iterator e){

???????while(e.hasNext()){

???????????System.out.println(e.next());

???????}

????}

}

在Hamster類中重寫父類的toString()方法斩松。

public class Hamster {

????private int hamsterNumber;

????public Hamster(int hamsterNumber){

???????this.hamsterNumber=hamsterNumber;

????}

????public String toString(){

???????return "This is Hamster #"+hamsterNumber;

????}

}

在HamsterMaze類中使用容器類加載Hamster類對象并輸出結(jié)果。

import java.util.ArrayList;

import java.util.List;

public class HamsterMaze {

????@SuppressWarnings("unchecked")

????public static void main(String[] args){

???????List list=new ArrayList();

???????for(int i=0;i<3;i++)

???????????list.add(new Hamster(i));

???????Printer.printAll(list.iterator());

????}

}

結(jié)果:

This is Hamster #0

This is Hamster #1

This is Hamster #2

3.一個(gè)實(shí)現(xiàn)toString()的通用的Bean

在作一個(gè)項(xiàng)目時(shí)發(fā)現(xiàn),許多bean需要實(shí)現(xiàn)toString()方法,就實(shí)現(xiàn)一個(gè)通用的bean,然后通過其他繼承即可觉既。

import java.lang.reflect.Field;

public class BaseBean {


????public String toString() {

???????StringBuffer sb = new StringBuffer();

???????try {

???????????Class t = this.getClass();

???????????Field[] fields = t.getDeclaredFields();

???????????for (int i = 0; i < fields.length; i++) {

??????????????Field field = fields[i];

??????????????field.setAccessible(true);

??????????????sb.append("{");

??????????????sb.append(field.getName());

??????????????sb.append(":");

??????????????if (field.getType() == Integer.class) {

??????????????????sb.append(field.getInt(this));

??????????????} else if (field.getType() == Long.class) {

??????????????????sb.append(field.getLong(this));

??????????????} else if (field.getType() == Boolean.class) {

??????????????????sb.append(field.getBoolean(this));

??????????????} else if (field.getType() == char.class) {

??????????????????sb.append(field.getChar(this));

??????????????} else if (field.getType() == Double.class) {

??????????????????sb.append(field.getDouble(this));

??????????????} else if (field.getType() == Float.class) {

??????????????????sb.append(field.getFloat(this));

??????????????} else

??????????????????sb.append(field.get(this));

??????????????sb.append("}");

???????????}

???????} catch (Exception e) {

???????????e.printStackTrace();

???????}

???????return sb.toString();

????}

}

測試類

public class TestBean extends BaseBean {

????private int id;

????public int getId() {

???????return id;

????}

????public void setId(int id) {

???????this.id = id;

????}

????public static void main(String[] args) {

???????TestBean testBean = new TestBean();

???????testBean.setId(9);

???????System.out.println(testBean.toString());

????}

}

結(jié)果

{id:9}


關(guān)于String ,StringBuffer的性能


博客分類:?java語言

通過使用一些輔助性工具來找到程序中的瓶頸谣旁,然后就可以對瓶頸部分的代碼進(jìn)行優(yōu)化。一般有兩種方案:即優(yōu)化代碼或更改設(shè)計(jì)方法抓谴。我們一般會選擇后者蛛壳,因?yàn)椴蝗フ{(diào)用以下代碼要比調(diào)用一些優(yōu)化的代碼更能提高程序的性能。而一個(gè)設(shè)計(jì)良好的程序能夠精簡代碼符欠,從而提高性能嫡霞。

下面將提供一些在JAVA程序的設(shè)計(jì)和編碼中,為了能夠提高JAVA程序的性能希柿,而經(jīng)常采用的一些方法和技巧诊沪。

1.對象的生成和大小的調(diào)整。

JAVA程序設(shè)計(jì)中一個(gè)普遍的問題就是沒有好好的利用JAVA語言本身提供的函數(shù)曾撤,從而常常會生成大量的對象(或?qū)嵗┒艘ΑS捎谙到y(tǒng)不僅要花時(shí)間生成對象,以后可能還需花時(shí)間對這些對象進(jìn)行垃圾回收和處理盾戴。因此寄锐,生成過多的對象將會給程序的性能帶來很大的影響。

例1:關(guān)于String ,StringBuffer尖啡,+和append

JAVA語言提供了對于String類型變量的操作橄仆。但如果使用不當(dāng),會給程序的性能帶來影響衅斩。如下面的語句:

String name=new String("HuangWeiFeng");

System.out.println(name+"is my name");

看似已經(jīng)很精簡了盆顾,其實(shí)并非如此。為了生成二進(jìn)制的代碼畏梆,要進(jìn)行如下的步驟和操作:

(1)?生成新的字符串?new String(STR_1);

(2)?復(fù)制該字符串;

(3)?加載字符串常量"HuangWeiFeng"(STR_2);

(4)?調(diào)用字符串的構(gòu)架器(Constructor);

(5)?保存該字符串到數(shù)組中(從位置0開始);

(6)?從java.io.PrintStream類中得到靜態(tài)的out變量;

(7)?生成新的字符串緩沖變量new StringBuffer(STR_BUF_1);

(8)?復(fù)制該字符串緩沖變量;

(9)?調(diào)用字符串緩沖的構(gòu)架器(Constructor);

(10)?保存該字符串緩沖到數(shù)組中(從位置1開始);

(11)?以STR_1為參數(shù)您宪,調(diào)用字符串緩沖(StringBuffer)類中的append方法;

(12)?加載字符串常量"is my name"(STR_3);

(13)?以STR_3為參數(shù),調(diào)用字符串緩沖(StringBuffer)類中的append方法;

(14)?對于STR_BUF_1執(zhí)行toString命令;

(15)?調(diào)用out變量中的println方法奠涌,輸出結(jié)果宪巨。

由此可以看出,這兩行簡單的代碼溜畅,就生成了STR_1,STR_2,STR_3,STR_4和STR_BUF_1五個(gè)對象變量捏卓。這些生成的類的實(shí)例一般都存放在堆中。堆要對所有類的超類慈格,類的實(shí)例進(jìn)行初始化怠晴,同時(shí)還要調(diào)用類極其每個(gè)超類的構(gòu)架器遥金。而這些操作都是非常消耗系統(tǒng)資源的。因此蒜田,對對象的生成進(jìn)行限制稿械,是完全有必要的。

經(jīng)修改冲粤,上面的代碼可以用如下的代碼來替換美莫。

StringBuffer name=new StringBuffer("HuangWeiFeng");

System.out.println(name.append("is my name.").toString());

系統(tǒng)將進(jìn)行如下的操作:

(1)?生成新的字符串緩沖變量new StringBuffer(STR_BUF_1);

(2)?復(fù)制該字符串緩沖變量;

(3)?加載字符串常量"HuangWeiFeng"(STR_1);

(4)?調(diào)用字符串緩沖的構(gòu)架器(Constructor);

(5)?保存該字符串緩沖到數(shù)組中(從位置1開始);

(6)?從java.io.PrintStream類中得到靜態(tài)的out變量;

(7)?加載STR_BUF_1;

(8)?加載字符串常量"is my name"(STR_2);

(9)?以STR_2為參數(shù),調(diào)用字符串緩沖(StringBuffer)實(shí)例中的append方法;

(10)?對于STR_BUF_1執(zhí)行toString命令(STR_3);

(11)調(diào)用out變量中的println方法梯捕,輸出結(jié)果茂嗓。

由此可以看出,經(jīng)過改進(jìn)后的代碼只生成了四個(gè)對象變量:STR_1,STR_2,STR_3和STR_BUF_1.你可能覺得少生成一個(gè)對象不會對程序的性能有很大的提高科阎。但下面的代碼段2的執(zhí)行速度將是代碼段1的2倍。因?yàn)榇a段1生成了八個(gè)對象忿族,而代碼段2只生成了四個(gè)對象锣笨。

代碼段1:

String name= new StringBuffer("HuangWeiFeng");

name+="is my";

name+="name";

代碼段2:

StringBuffer name=new StringBuffer("HuangWeiFeng");

name.append("is my");

name.append("name.").toString();

因此,充分的利用JAVA提供的庫函數(shù)來優(yōu)化程序道批,對提高JAVA程序的性能時(shí)非常重要的.其注意點(diǎn)主要有如下幾方面错英;?

4.finalize方法

該方法用于釋放資源。因?yàn)闊o法確定該方法什么時(shí)候被調(diào)用隆豹,很少使用椭岩。

1. finalize的作用


finalize()是Object的protected方法,子類可以覆蓋該方法以實(shí)現(xiàn)資源清理工作璃赡,GC在回收對象之前調(diào)用該方法判哥。

finalize()與C++中的析構(gòu)函數(shù)不是對應(yīng)的。C++中的析構(gòu)函數(shù)調(diào)用的時(shí)機(jī)是確定的(對象離開作用域或delete掉)碉考,但Java中的finalize的調(diào)用具有不確定性

不建議用finalize方法完成“非內(nèi)存資源”的清理工作塌计,但建議用于:① 清理本地對象(通過JNI創(chuàng)建的對象);② 作為確保某些非內(nèi)存資源(如Socket侯谁、文件等)釋放的一個(gè)補(bǔ)充:在finalize方法中顯式調(diào)用其他資源釋放方法锌仅。其原因可見下文[finalize的問題]

2. finalize的問題

一些與finalize相關(guān)的方法,由于一些致命的缺陷墙贱,已經(jīng)被廢棄了热芹,如System.runFinalizersOnExit()方法、Runtime.runFinalizersOnExit()方法

System.gc()與System.runFinalization()方法增加了finalize方法執(zhí)行的機(jī)會惨撇,但不可盲目依賴它們

Java語言規(guī)范并不保證finalize方法會被及時(shí)地執(zhí)行伊脓、而且根本不會保證它們會被執(zhí)行

finalize方法可能會帶來性能問題。因?yàn)镴VM通常在單獨(dú)的低優(yōu)先級線程中完成finalize的執(zhí)行

對象再生問題:finalize方法中串纺,可將待回收對象賦值給GC Roots可達(dá)的對象引用丽旅,從而達(dá)到對象再生的目的

finalize方法至多由GC執(zhí)行一次(用戶當(dāng)然可以手動調(diào)用對象的finalize方法椰棘,但并不影響GC對finalize的行為)

3. finalize的執(zhí)行過程(生命周期)


(1) 首先,大致描述一下finalize流程:當(dāng)對象變成(GC Roots)不可達(dá)時(shí)榄笙,GC會判斷該對象是否覆蓋了finalize方法邪狞,若未覆蓋,則直接將其回收茅撞。否則帆卓,若對象未執(zhí)行過finalize方法,將其放入F-Queue隊(duì)列米丘,由一低優(yōu)先級線程執(zhí)行該隊(duì)列中對象的finalize方法剑令。執(zhí)行finalize方法完畢后,GC會再次判斷該對象是否可達(dá)拄查,若不可達(dá)吁津,則進(jìn)行回收,否則堕扶,對象“復(fù)活”碍脏。

(2) 具體的finalize流程:

對象可由兩種狀態(tài),涉及到兩類狀態(tài)空間稍算,一是終結(jié)狀態(tài)空間?F = {unfinalized, finalizable, finalized}典尾;二是可達(dá)狀態(tài)空間?R = {reachable, finalizer-reachable, unreachable}。各狀態(tài)含義如下:

unfinalized: 新建對象會先進(jìn)入此狀態(tài)糊探,GC并未準(zhǔn)備執(zhí)行其finalize方法钾埂,因?yàn)樵搶ο笫强蛇_(dá)的

finalizable: 表示GC可對該對象執(zhí)行finalize方法,GC已檢測到該對象不可達(dá)科平。正如前面所述褥紫,GC通過F-Queue隊(duì)列和一專用線程完成finalize的執(zhí)行

finalized: 表示GC已經(jīng)對該對象執(zhí)行過finalize方法

reachable: 表示GC Roots引用可達(dá)

finalizer-reachable(f-reachable):表示不是reachable,但可通過某個(gè)finalizable對象可達(dá)

unreachable:對象不可通過上面兩種途徑可達(dá)

狀態(tài)變遷圖:

變遷說明:

新建對象首先處于[reachable, unfinalized]狀態(tài)(A)

隨著程序的運(yùn)行瞪慧,一些引用關(guān)系會消失故源,導(dǎo)致狀態(tài)變遷,從reachable狀態(tài)變遷到f-reachable(B, C, D)或unreachable(E, F)狀態(tài)

若JVM檢測到處于unfinalized狀態(tài)的對象變成f-reachable或unreachable汞贸,JVM會將其標(biāo)記為finalizable狀態(tài)(G,H)绳军。若對象原處于[unreachable, unfinalized]狀態(tài),則同時(shí)將其標(biāo)記為f-reachable(H)矢腻。

在某個(gè)時(shí)刻门驾,JVM取出某個(gè)finalizable對象,將其標(biāo)記為finalized并在某個(gè)線程中執(zhí)行其finalize方法多柑。由于是在活動線程中引用了該對象奶是,該對象將變遷到(reachable, finalized)狀態(tài)(K或J)。該動作將影響某些其他對象從f-reachable狀態(tài)重新回到reachable狀態(tài)(L, M, N)

處于finalizable狀態(tài)的對象不能同時(shí)是unreahable的,由第4點(diǎn)可知聂沙,將對象finalizable對象標(biāo)記為finalized時(shí)會由某個(gè)線程執(zhí)行該對象的finalize方法秆麸,致使其變成reachable。這也是圖中只有八個(gè)狀態(tài)點(diǎn)的原因

程序員手動調(diào)用finalize方法并不會影響到上述內(nèi)部標(biāo)記的變化及汉,因此JVM只會至多調(diào)用finalize一次沮趣,即使該對象“復(fù)活”也是如此。程序員手動調(diào)用多少次不影響JVM的行為

若JVM檢測到finalized狀態(tài)的對象變成unreachable坷随,回收其內(nèi)存(I)

若對象并未覆蓋finalize方法房铭,JVM會進(jìn)行優(yōu)化,直接回收對象(O)

注:System.runFinalizersOnExit()等方法可以使對象即使處于reachable狀態(tài)温眉,JVM仍對其執(zhí)行finalize方法

4. 一些代碼示例

(1) 對象復(fù)活

[java]view plaincopy



publicclass?GC?{??


publicstatic?GC?SAVE_HOOK?=null;??


publicstaticvoid?main(String[]?args)throws?InterruptedException?{??

SAVE_HOOK?=new?GC();??

SAVE_HOOK?=null;??

????????System.gc();??

Thread.sleep(500);??

if?(null?!=?SAVE_HOOK)?{//此時(shí)對象應(yīng)該處于(reachable,?finalized)狀態(tài)??

System.out.println("Yes?,?I?am?still?alive");??

}else?{??

System.out.println("No?,?I?am?dead");??

????????}??

SAVE_HOOK?=null;??

????????System.gc();??

Thread.sleep(500);??

if?(null?!=?SAVE_HOOK)?{??

System.out.println("Yes?,?I?am?still?alive");??

}else?{??

System.out.println("No?,?I?am?dead");??

????????}??

????}??


@Override??

protectedvoid?finalize()throws?Throwable?{??

super.finalize();??

System.out.println("execute?method?finalize()");??

SAVE_HOOK?=this;??

????}??

}?

5.equals方法

該方法是非常重要的一個(gè)方法缸匪。一般equals和==是不一樣的,但是在Object中兩者是一樣的类溢。子類一般都要重寫這個(gè)方法凌蔬。

6.hashCode方法

該方法用于哈希查找,可以減少在查找中使用equals的次數(shù)闯冷,重寫了equals方法一般都要重寫hashCode方法龟梦。這個(gè)方法在一些具有哈希功能的Collection中用到。

一般必須滿足obj1.equals(obj2)==true窃躲。可以推出obj1.hash- Code()==obj2.hashCode()钦睡,但是hashCode相等不一定就滿足equals蒂窒。不過為了提高效率,應(yīng)該盡量使上面兩個(gè)條件接近等價(jià)荞怒。

如果不重寫hashcode(),在HashSet中添加兩個(gè)equals的對象洒琢,會將兩個(gè)對象都加入進(jìn)去。

7.wait方法

wait方法就是使當(dāng)前線程等待該對象的鎖褐桌,當(dāng)前線程必須是該對象的擁有者衰抑,也就是具有該對象的鎖。wait()方法一直等待荧嵌,直到獲得鎖或者被中斷呛踊。wait(long timeout)設(shè)定一個(gè)超時(shí)間隔,如果在規(guī)定時(shí)間內(nèi)沒有獲得鎖就返回啦撮。

調(diào)用該方法后當(dāng)前線程進(jìn)入睡眠狀態(tài)谭网,直到以下事件發(fā)生。

(1)其他線程調(diào)用了該對象的notify方法赃春。

(2)其他線程調(diào)用了該對象的notifyAll方法愉择。

(3)其他線程調(diào)用了interrupt中斷該線程。

(4)時(shí)間間隔到了。

此時(shí)該線程就可以被調(diào)度了锥涕,如果是被中斷的話就拋出一個(gè)InterruptedException異常衷戈。

wait方法是Object對象的方法。線程與鎖是分不開的层坠,線程的同步殖妇、等待、喚醒都與對象鎖是密不可分的窿春。wait方法會將當(dāng)前線程放入wait set拉一,等待被喚醒,并放棄lock對象上的所有同步聲明旧乞,當(dāng)前線程會因?yàn)榫€程調(diào)度的原因處于休眠狀態(tài)而不可用蔚润。只有通過以下四個(gè)方法可以主動喚醒:?

1. notify?

2. notifyAll?

3. Thread.interrupt()?

4. 等待時(shí)間過完。

當(dāng)線程被喚醒后尺栖,線程就從wait set中移除了并且重新獲得線程調(diào)度能力嫡纠,同時(shí)像其它線程一樣持有object的鎖。

一段synchronized的代碼被一個(gè)線程執(zhí)行之前延赌,他要先拿到執(zhí)行這段代碼的權(quán)限除盏,?

在Java里邊就是拿到某個(gè)同步對象的鎖(一個(gè)對象只有一把鎖);?

如果這個(gè)時(shí)候同步對象的鎖被其他線程拿走了挫以,他(這個(gè)線程)就只能等了(線程阻塞在鎖池等待隊(duì)列中)者蠕。?

取到鎖后,他就開始執(zhí)行同步代碼(被synchronized修飾的代碼)掐松;?

線程執(zhí)行完同步代碼后馬上就把鎖還給同步對象踱侣,其他在鎖池中等待的某個(gè)線程就可以拿到鎖執(zhí)行同步代碼了。?

這樣就保證了同步代碼在統(tǒng)一時(shí)刻只有一個(gè)線程在執(zhí)行大磺。

這里就需要補(bǔ)充一下對象鎖和類鎖的區(qū)別抡句。?

事實(shí)上,synchronized修飾非靜態(tài)方法杠愧、同步代碼塊的synchronized (this)用法和synchronized (非this對象)的用法鎖的是對象待榔,線程想要執(zhí)行對應(yīng)同步代碼,需要獲得對象鎖流济。

線程正常結(jié)束后锐锣,會使以這個(gè)線程對象運(yùn)行的wait()等待,退出等待狀態(tài)绳瘟!而如果在運(yùn)行wait()之前刺下,線程已經(jīng)結(jié)束了,則這個(gè)wait就沒有程序喚醒了稽荧。?

原碼里的join()方法橘茉,實(shí)際上就是運(yùn)行的 wait(). 需要運(yùn)行join的線程運(yùn)行join方法工腋,實(shí)際上是在此線程上調(diào)用了需要加入的線程對象的wait()方法,加入的線程運(yùn)行完后畅卓,自然從wait退出了擅腰。

到此,就得出了我的結(jié)論:

1 線程對象的wait()方法運(yùn)行后翁潘,可以不用其notify()方法退出趁冈,會在線程結(jié)束后,自動退出拜马。

2 線程間的等待喚醒機(jī)制渗勘,最好不要用線程對象做同步鎖!

首先我們看一個(gè)實(shí)例:

public class TestDemo{

public static void main(String [ ]args) throws Interrupted Exception{?

?? ? ? MyThread myThread =new MyThread();?

?? ? ? System.out.println("before");?

?? ? ? myThread.start();? ? ? ??

? ? ? ?System.out.println("after");? ?

?}

????static class MyThread extends Thread{public void run(){

? ? ? ? ? ? synchronized (this) {

? ? ? ? ? ? ? ? ? ?for(inti=0;i<3;i++){? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? System.out.println("number:"+ i);? ? ? ? ? ? ??

? }? ? ? ? ??

? }? ? ??

? }? ?

?}}

輸出的結(jié)果是:?

before?

after?

number:0?

number:1?

number:2

首先是Main線程具有搶占cpu資源俩莽,然后執(zhí)行完后旺坠,在開始執(zhí)行子線程。

實(shí)例2:

public class TestDemo{

?public static void main(String []args) throws Interrupted Exception{? ? ? ??

????????MyThread myThread =new MyThread();? ? ? ??

????????System.out.println("before");? ? ? ??

????????myThread.start();? ? ? ??

????????synchronized (myThread) {??

? ? ? ? myThread.wait();? ? ? ?

??}? ? ? ?

?System.out.println("after");? ?

?}

?static class MyThread extends Thread{

????public void run(){? ? ? ? ??

????? synchronized (this) {

????????for(int i=0;i<3;i++){

? ? ? ? ? ? ?System.out.println("number:"+ i);? ? ? ? ? ? ? ?

?}? ? ? ? ? ?

?}? ? ? ??

}??

? }}

before?

number:0?

number:1?

number:2?

after

我們調(diào)用wait方法扮超,Main線程會釋放當(dāng)前鎖取刃,進(jìn)入wait set。然后子線程開始運(yùn)行出刷,當(dāng)子線程運(yùn)行完畢后璧疗,會把鎖歸還。

8.notify方法

該方法喚醒在該對象上等待的某個(gè)線程馁龟。

對于wait()和notify()的理解崩侠,還是要從jdk官方文檔中開始,在Object類方法中有:

void notify()?

Wakes up a single thread that is waiting on this object’s monitor.?

譯:喚醒在此對象監(jiān)視器上等待的單個(gè)線程

void notifyAll()?

Wakes up all threads that are waiting on this object’s monitor.?

譯:喚醒在此對象監(jiān)視器上等待的所有線程

void wait( )?

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll( ) method for this object.?

譯:導(dǎo)致當(dāng)前的線程等待坷檩,直到其他線程調(diào)用此對象的notify( ) 方法或 notifyAll( ) 方法

void wait(long timeout)?

Causes the current thread to wait until either another thread invokes the notify( ) method or the notifyAll( ) method for this object, or a specified amount of time has elapsed.?

譯:導(dǎo)致當(dāng)前的線程等待却音,直到其他線程調(diào)用此對象的notify() 方法或 notifyAll() 方法,或者指定的時(shí)間過完淌喻。

void wait(long timeout, int nanos)?

Causes the current thread to wait until another thread invokes the notify( ) method or the notifyAll( ) method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.?

譯:導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對象的notify( ) 方法或 notifyAll( ) 方法雀摘,或者其他線程打斷了當(dāng)前線程裸删,或者指定的時(shí)間過完。

上面是官方文檔的簡介阵赠,下面我們根據(jù)官方文檔總結(jié)一下:

wait( )涯塔,notify( ),notifyAll( )都不屬于Thread類清蚀,而是屬于Object基礎(chǔ)類匕荸,也就是每個(gè)對象都有wait( ),notify( )枷邪,notifyAll( ) 的功能榛搔,因?yàn)槊總€(gè)對象都有鎖,鎖是每個(gè)對象的基礎(chǔ),當(dāng)然操作鎖的方法也是最基礎(chǔ)了践惑。

當(dāng)需要調(diào)用以上的方法的時(shí)候腹泌,一定要對競爭資源進(jìn)行加鎖,如果不加鎖的話尔觉,則會報(bào) IllegalMonitorStateException 異常

當(dāng)想要調(diào)用wait( )進(jìn)行線程等待時(shí)凉袱,必須要取得這個(gè)鎖對象的控制權(quán)(對象監(jiān)視器),一般是放到synchronized(obj)代碼中侦铜。

在while循環(huán)里而不是if語句下使用wait专甩,這樣,會在線程暫投ど裕恢復(fù)后都檢查wait的條件涤躲,并在條件實(shí)際上并未改變的情況下處理喚醒通知

調(diào)用obj.wait( )釋放了obj的鎖,否則其他線程也無法獲得obj的鎖嫁盲,也就無法在synchronized(obj){ obj.notify() } 代碼段內(nèi)喚醒A篓叶。

notify( )方法只會通知等待隊(duì)列中的第一個(gè)相關(guān)線程(不會通知優(yōu)先級比較高的線程)

notifyAll( )通知所有等待該競爭資源的線程(也不會按照線程的優(yōu)先級來執(zhí)行)

假設(shè)有三個(gè)線程執(zhí)行了obj.wait( ),那么obj.notifyAll( )則能全部喚醒tread1羞秤,thread2缸托,thread3,但是要繼續(xù)執(zhí)行obj.wait()的下一條語句瘾蛋,必須獲得obj鎖俐镐,因此,tread1哺哼,thread2佩抹,thread3只有一個(gè)有機(jī)會獲得鎖繼續(xù)執(zhí)行,例如tread1取董,其余的需要等待thread1釋放obj鎖之后才能繼續(xù)執(zhí)行棍苹。

當(dāng)調(diào)用obj.notify/notifyAll后,調(diào)用線程依舊持有obj鎖茵汰,因此枢里,thread1,thread2蹂午,thread3雖被喚醒栏豺,但是仍無法獲得obj鎖。直到調(diào)用線程退出synchronized塊豆胸,釋放obj鎖后奥洼,thread1,thread2晚胡,thread3中的一個(gè)才有機(jī)會獲得鎖繼續(xù)執(zhí)行灵奖。

2.wait和notify簡單使用示例

public class WaitNotifyTest{

?// 在多線程間共享的對象上使用wait private String[ ]? shareObj = { "true" };

? ? public static void main(String[] args) {

? ? ? ? WaitNotifyTest test = new WaitNotifyTest();

? ? ? ? ThreadWait threadWait1 = test.new ThreadWait("wait thread1");

? ? ? ? threadWait1.setPriority(2);

? ? ? ? ThreadWait threadWait2 = test.new ThreadWait("wait thread2");

? ? ? ? threadWait2.setPriority(3);

? ? ? ? ThreadWait threadWait3 = test.new ThreadWait("wait thread3");

? ? ? ? threadWait3.setPriority(4);

? ? ? ? ThreadNotify threadNotify = test.new ThreadNotify("notify thread");

? ? ? ? threadNotify.start();

? ? ? ? threadWait1.start();

? ? ? ? threadWait2.start();

? ? ? ? threadWait3.start();

? ? }

? ? class ThreadWait extends Thread {

? ? ? ? public ThreadWait(String name){

? ? ? ? ? ? super(name);

? ? ? ? }

? ? ? ? public void run() {

? ? ? ? ? ? synchronized (shareObj) {

? ? ? ? ? ? ? ? while ("true".equals(shareObj[0])) {

? ? ? ? ? ? ? ? ? ? System.out.println("線程"+ this.getName() + "開始等待");

? ? ? ? ? ? ? ? ? ? long startTime = System.currentTimeMillis();

? ? ? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? ? ? shareObj.wait();

? ? ? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? long endTime = System.currentTimeMillis();

? ? ? ? ? ? ? ? ? ? System.out.println("線程" + this.getName()

? ? ? ? ? ? ? ? ? ? ? ? ? ? + "等待時(shí)間為:" + (endTime - startTime));

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? System.out.println("線程" + getName() + "等待結(jié)束");

? ? ? ? }

? ? }

? ? class ThreadNotify extends Thread {

? ? ? ? public ThreadNotify(String name){

? ? ? ? ? ? super(name);

? ? ? ? }

? ? ? ? public void run() {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? // 給等待線程等待時(shí)間? ? ? ? ? ? ? ? sleep(3000);

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? ? ? synchronized (shareObj) {

? ? ? ? ? ? ? ? System.out.println("線程" + this.getName() + "開始準(zhǔn)備通知");

? ? ? ? ? ? ? ? shareObj[0] = "false";

? ? ? ? ? ? ? ? shareObj.notifyAll();

? ? ? ? ? ? ? ? System.out.println("線程" + this.getName() + "通知結(jié)束");

? ? ? ? ? ? }

? ? ? ? ? ? System.out.println("線程" + this.getName() + "運(yùn)行結(jié)束");

? ? ? ? }

? ? }

}

運(yùn)行結(jié)果:

線程wait thread1開始等待

線程wait thread3開始等待

線程wait thread2開始等待

線程notify thread開始準(zhǔn)備通知

線程notify thread通知結(jié)束

線程notify thread運(yùn)行結(jié)束

線程wait thread2等待時(shí)間為:2998線程wait thread2等待結(jié)束

線程wait thread3等待時(shí)間為:2998線程wait thread3等待結(jié)束

線程wait thread1等待時(shí)間為:3000線程wait thread1等待結(jié)束

9.notifyAll方法

該方法喚醒在該對象上等待的所有線程

在Java語言中notifyAll()方法的實(shí)際作用如下:

1.notifyAll():?Wakes up all threads that are waiting on this object's monitor嚼沿;

2.當(dāng)一個(gè)線程使用的同步方法中用到某個(gè)變量,而此變量又需要其它線程修改后才能符合本線程的需要,則可以在同步方法中調(diào)用wait()方法,使本線程等待,并允許其它線程調(diào)用這個(gè)同步方法

3.其它線程在使用這個(gè)同步方法不需要等待,當(dāng)它使用完這個(gè)同步方法時(shí),用notifyAll()通知所有由于使用這個(gè)同步方法而處于等待的線程結(jié)束,再次使用這個(gè)同步方法

4.如果使第一個(gè)處于等待的線程結(jié)束等待,則調(diào)用方法notify()

Java是一門面向?qū)ο缶幊陶Z言,不僅吸收了C++語言的各種優(yōu)點(diǎn)桑寨,還摒棄了C++里難以理解的多繼承伏尼、指針等概念,因此Java語言具有功能強(qiáng)大和簡單易用兩個(gè)特征尉尾。Java語言作為靜態(tài)面向?qū)ο缶幊陶Z言的代表爆阶,極好地實(shí)現(xiàn)了面向?qū)ο罄碚摚试S程序員以優(yōu)雅的思維方式進(jìn)行復(fù)雜的編程沙咏。

Java具有簡單性辨图、面向?qū)ο蟆⒎植际街辍⒔研怨屎印踩浴⑵脚_獨(dú)立與可移植性吆豹、多線程鱼的、動態(tài)性等特點(diǎn) ?。Java可以編寫桌面應(yīng)用程序痘煤、Web應(yīng)用程序凑阶、分布式系統(tǒng)和嵌入式系統(tǒng)應(yīng)用程序等。

?在Java多線程中衷快,notify() 與 notifyAll() 是比較重要的方法宙橱,通常與wait方法配合使用,它們只能在同步域里面調(diào)用否則會出現(xiàn)異常IllegalMonitorStateException

下面說說他們的功能:

notify :作用是喚醒指定某個(gè)線程蘸拔,在一般實(shí)際使用情況下此方法用的不多师郑,因?yàn)橐话悴恢粫嬖?、2個(gè)線程调窍,當(dāng)線程多的時(shí)候使用此方法維護(hù)起來就很麻煩宝冕,很容易造成死鎖。

notifyAll : 作用是喚醒指定鎖上等待執(zhí)行的所有線程邓萨,打個(gè)比方地梨,此時(shí)有線程 T1 線程 T2 線程 T3 現(xiàn)在假設(shè)T2與T3線程先執(zhí)行并且是處于wait等待狀態(tài),他們要等T1去喚醒他們先誉,由于他們兩都是處于wait狀態(tài)湿刽,除非有其他線程喚醒它們否則他們會一直處于等待狀態(tài)的烁,如果此時(shí)T1已經(jīng)執(zhí)行并且已經(jīng)調(diào)用notifyAll方法褐耳,就會喚醒T2與T3,可能這時(shí)會有疑問線程T1是怎么能夠喚醒其他兩個(gè)線程的呢渴庆?首先會有個(gè)前提條件 T1铃芦、T2雅镊、T3線程都是處于同一個(gè)鎖域,因?yàn)槿绻皇翘幱谕粋€(gè)鎖域調(diào)用notifyAll或者是notify會報(bào)錯(cuò)的刃滓,代碼例如這樣:

T1:

// 之所以加個(gè)while 以及flag標(biāo)示是因?yàn)榭赡艽嬖赥2執(zhí)行完就執(zhí)行T1的情況或者是先執(zhí)行了T1,這樣就會造成死鎖,因?yàn)門1一旦先執(zhí)行那就沒有線程把T2仁烹、T3喚醒了,T2 T3則一直等待有個(gè)線程喚醒他咧虎,而此時(shí)已沒有線程能喚醒他們了卓缰。

while(true){ ??

if(flag){

synchronized(lock){

println("執(zhí)行了T1");

notifyAll();

flag = false;

? ? ? ? ? }

}

}

// 還能這樣,將T2砰诵,T3線程傳入T1中征唬,調(diào)用它們的join方法等待他們執(zhí)行完才執(zhí)行notifyAll(),相比前一個(gè)代碼這個(gè)代碼更直接些茁彭,但是存在多個(gè)不同線程時(shí)會很麻煩总寒,因?yàn)橐阉麄冏鳛閰⑷雮魅牖蛘哒{(diào)用。

T1:

T2 t2;

T3 t3;

synchronized(lock){

t2.join();

t3.join();

println("執(zhí)行了T1");

notifyAll();

}

T2:

synchronized(lock){

flag?=?true;

wait();

println("執(zhí)行了T2");

}

T3:

synchronized(lock){

flag?=?true;

wait();

println("執(zhí)行了T3");

}

注意:當(dāng)某個(gè)線程調(diào)用wait()方法之后會自動釋放當(dāng)前線程占用的鎖理肺。



? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 注:本文收集于各大網(wǎng)絡(luò),一切只為了學(xué)習(xí)!謝謝各位大神.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摄闸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妹萨,更是在濱河造成了極大的恐慌年枕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眠副,死亡現(xiàn)場離奇詭異画切,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)囱怕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門霍弹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人娃弓,你說我怎么就攤上這事典格。” “怎么了台丛?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵耍缴,是天一觀的道長。 經(jīng)常有香客問我挽霉,道長防嗡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任侠坎,我火速辦了婚禮蚁趁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘实胸。我一直安慰自己他嫡,他們只是感情好番官,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钢属,像睡著了一般徘熔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淆党,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天酷师,我揣著相機(jī)與錄音,去河邊找鬼染乌。 笑死窒升,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慕匠。 我是一名探鬼主播饱须,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼台谊!你這毒婦竟也來了蓉媳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锅铅,失蹤者是張志新(化名)和其女友劉穎酪呻,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盐须,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玩荠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贼邓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阶冈。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖塑径,靈堂內(nèi)的尸體忽然破棺而出女坑,到底是詐尸還是另有隱情,我是刑警寧澤统舀,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布匆骗,位于F島的核電站,受9級特大地震影響誉简,放射性物質(zhì)發(fā)生泄漏碉就。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一闷串、第九天 我趴在偏房一處隱蔽的房頂上張望瓮钥。 院中可真熱鬧,春花似錦、人聲如沸骏庸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽具被。三九已至,卻和暖如春只损,著一層夾襖步出監(jiān)牢的瞬間一姿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工跃惫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叮叹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓爆存,卻偏偏與公主長得像蛉顽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子先较,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法携冤,類相關(guān)的語法,內(nèi)部類的語法闲勺,繼承相關(guān)的語法曾棕,異常的語法,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • JAVA面試題 1菜循、作用域public,private,protected,以及不寫時(shí)的區(qū)別答:區(qū)別如下:作用域 ...
    JA尐白閱讀 1,154評論 1 0
  • 小編費(fèi)力收集:給你想要的面試集合 1.C++或Java中的異常處理機(jī)制的簡單原理和應(yīng)用翘地。 當(dāng)JAVA程序違反了JA...
    八爺君閱讀 4,592評論 1 114
  • 我看到躍動的時(shí)間 正在貓的眼睛里靜止 時(shí)間第一次是這樣的姿態(tài)出現(xiàn) 我同它無聲的攀談 順著陽光傾瀉的金色舞步 徜徉在...
    方潭閱讀 473評論 0 2
  • 什么時(shí)候才會讓你徹底體會到自己不再是女孩,而是已經(jīng)步入了女人的階段癌幕,我想大概就是懷孕當(dāng)媽媽起吧衙耕,第一次懷疑自己懷孕...
    清風(fēng)伊笑閱讀 762評論 0 0