国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 Java Java基礎(chǔ) Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)

Feb 24, 2021 am 10:10 AM
java 線程安全

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)

免費(fèi)學(xué)習(xí)推薦:java基礎(chǔ)教學(xué)

  • #線程安全基礎(chǔ)
    • 1.線程安全問題
    • 2.帳戶取款案例
    • 3.同步程式碼區(qū)塊synchronized
    • #synchronized的理解
    java中有三大變數(shù)的執(zhí)行緒安全性問題
  • 在實(shí)例方法上使用synchronized
  • 總結(jié)
  • #面試題
  • 4.死鎖
  • 5.開發(fā)中該怎麼解決執(zhí)行緒安全性問題
  • 6.守護(hù)執(zhí)行緒
# 7.定時器

8.實(shí)作執(zhí)行緒的第三種方式:實(shí)作Callable介面

#9.Object類別中的wait和notify方法


10.生產(chǎn)者和消費(fèi)者


Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)1.線程安全性問題

2.1、為什麼這個才是重點(diǎn)?
??以後在開發(fā)中,我們的專案都是運(yùn)行在伺服器當(dāng)中,而伺服器已經(jīng)將執(zhí)行緒的定義,執(zhí)行緒物件的創(chuàng)建,執(zhí)行緒的啟動等,都已經(jīng)實(shí)現(xiàn)了。這些程式碼我們都不需要寫。
??最重要的是:你要知道,你寫的程式需要放到一個多執(zhí)行緒的環(huán)境下運(yùn)行,你更需要關(guān)注的是這些資料在多執(zhí)行緒並發(fā)的環(huán)境下是否是安全的。 (重點(diǎn):*****)
2.2、何時資料在多執(zhí)行緒並發(fā)的環(huán)境下會存在安全性問題呢?

??三個條件:
??條件1:多執(zhí)行緒並發(fā)。
??條件2:有共享資料。 ??條件3:共享資料有修改的行為。
??滿足以上3個條件之後,就會存在執(zhí)行緒安全性問題。
2.3、怎麼解決執(zhí)行緒安全問題呢?
當(dāng)多執(zhí)行緒並發(fā)的環(huán)境下,有共享數(shù)據(jù),而這個數(shù)據(jù)還會被修改,此時就存在線程安全問題,怎麼解決這個問題? ??執(zhí)行緒排隊(duì)執(zhí)行。 (不能併發(fā))。
??用排隊(duì)執(zhí)行解決線程安全問題。
??這種機(jī)制稱為:執(zhí)行緒同步機(jī)制。 ??專業(yè)術(shù)語叫做:
執(zhí)行緒同步,其實(shí)就是執(zhí)行緒不能並發(fā)了,執(zhí)行緒必須排隊(duì)執(zhí)行
。
??怎麼解決線程安全性問題呀?
??使用「執(zhí)行緒同步機(jī)制」。

??線程同步就是線程排隊(duì)了,線程排隊(duì)了就會犧牲一部分效率,沒辦法,資料安全第一位,只有資料安全了,我們才可以談效率。數(shù)據(jù)不安全,沒有效率的事兒。
2.4、說到線程同步這塊,涉及到這兩個專業(yè)術(shù)語:

非同步程式設(shè)計(jì)模型:
??線程t1和線程t2,各自執(zhí)行各自的, t1不管t2,t2不管t1, ??誰也不需要等誰,這種程式設(shè)計(jì)模型叫做:非同步程式設(shè)計(jì)模型。 ??其實(shí)就是:多執(zhí)行緒並發(fā)(效率較高。)

同步程式設(shè)計(jì)模型:

??執(zhí)行緒t1和執(zhí)行緒t2,在執(zhí)行緒t1執(zhí)行的時候,必須等待t2線程執(zhí)行結(jié)束,或者說在t2線程執(zhí)行的時候,必須等待t1線程執(zhí)行結(jié)束,兩個線程之間發(fā)生了等待關(guān)係,這就是同步編程模型。效率較低。線程排隊(duì)執(zhí)行。

非同步就是並發(fā)。同步就是排隊(duì)。

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)2.帳戶提款案例

Account類別

package?ThreadSafe;public?class?Account?{
	//賬號
	private?String?actno;
	//余額
	private?double?balance;
	
	public?Account(String?actno,?double?balance)?{
		super();
		this.actno?=?actno;
		this.balance?=?balance;
	}
	public?String?getActno()?{
		return?actno;
	}
	public?void?setActno(String?actno)?{
		this.actno?=?actno;
	}
	public?double?getBalance()?{
		return?balance;
	}
	public?void?setBalance(double?balance)?{
		this.balance?=?balance;
	}
	//取款的方法
	public?void?withdraw(double?money){
		//t1和t2并發(fā)執(zhí)行這個方法(t1和t2是兩個棧?,兩個棧操作堆中同一個對象)
		//取款之前的余額
		double?before=this.getBalance();
		//取款之后的余額
		double?after=before-money;
		//模擬一下網(wǎng)絡(luò)延遲,會出現(xiàn)問題
		try?{
			Thread.sleep(1000);
		}?catch?(InterruptedException?e)?{
			//?TODO?Auto-generated?catch?block
			e.printStackTrace();
		}
		//更新余額
		//思考:t1執(zhí)行到這里了,但還沒有來得及執(zhí)行這行代碼,t2線程進(jìn)來withdraw方法了,此時一定出問題
		this.setBalance(after);
	}}AccountThread類public?class?AccountThread?extends?Thread{
	//兩個線程必須共享一個賬戶對象
	private?Account?act;
	//通過構(gòu)造方法傳遞過來賬戶對象
	public?AccountThread(Account?act)?{
		this.act?=?act;
	}
	@Override
	public?void?run()?{
		//假設(shè)取款5000
		double?money=5000;
		//多線程執(zhí)行這個方法
		act.withdraw(money);
		System.out.println(Thread.currentThread().getName()+"賬戶"+act.getActno()+"取款成功"+act.getBalance());
	}}
Test類別

public?class?Test?{
	public?static?void?main(String[]?args)?{
		//創(chuàng)建賬戶對象
		Account?act=new?Account("act-001",10000);
		//創(chuàng)建兩個線程
		Thread?t1=new?AccountThread(act);
		Thread?t2=new?AccountThread(act);
		
		t1.setName("t1");
		t2.setName("t2");
		//啟動兩個線程執(zhí)行
		t1.start();
		t2.start();
	}}


#3.同步程式碼區(qū)塊synchronized

synchronized的理解
//以下這幾行程式碼必須是執(zhí)行緒排隊(duì)的,不能並發(fā)
//
一個執(zhí)行緒把這裡的程式碼全部執(zhí)行結(jié)束後,另一個執(zhí)行緒才能進(jìn)來

/*
執(zhí)行緒同步機(jī)制的語法是 synchronized( ){

//執(zhí)行緒同步程式碼區(qū)塊。
}

synchronized後面小括號中傳的這個數(shù)據(jù)是相當(dāng)關(guān)鍵的,

這個數(shù)據(jù)必須是多執(zhí)行緒共享的數(shù)據(jù),才能達(dá)到多執(zhí)行緒排隊(duì)。

()中寫什麼? ### 那要看你想讓哪些線程同步### 假設(shè)t1、t2、t3、t4、t5有5個線程### 你只希望t1 t2 t3排隊(duì),t4 t5不需要排隊(duì),怎麼辦## # 你一定要在()中寫一個t1 t2 t3共享的對象,而這個對象對於t4 t5來說不是??共享的### 這裡的共享對像是賬戶對象### 帳戶對像是共享的,this是賬戶物件### 有時不一定是this,這裡只要是多執(zhí)行緒共享的那個物件就行###
		synchronized(this){
			double?before=this.getBalance();
			double?after=before-money;
			try?{
				Thread.sleep(1000);
			}?catch?(InterruptedException?e)?{
				//?TODO?Auto-generated?catch?block
				e.printStackTrace();
			}
			this.setBalance(after);
		}

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)
在java語言中,任何對象都有一把鎖,其實(shí)這把鎖就是一個標(biāo)記,(只是把它叫做鎖)
100個對象,100個鎖,1個對象1把鎖。
以上代碼的執(zhí)行原理是什么呢?
1.假設(shè)t1和t2線程并發(fā),開始執(zhí)行以上代碼的時候,肯定有一個先一個后,
2.假設(shè)t1先執(zhí)行了,遇到了synchronized,這個時候自動找后面共享對象的對象鎖,找到之后,并占有這把鎖,然后執(zhí)行同步代碼塊中的程序,在程序執(zhí)行過程中一直都占有這把鎖,直到同步代碼塊執(zhí)行結(jié)束,這把鎖才會釋放。
3.假設(shè)t1已經(jīng)占有這把鎖,此時t2也遇到synchronized關(guān)鍵字,也會去占有后面共享對象的這把鎖,結(jié)果這把鎖被t1占有,t2只能在同步代碼塊外邊等待t1的結(jié)束,直到t1把同步代碼塊執(zhí)行結(jié)束了,t1會歸還這把鎖,此時t2終于等到這把鎖,然后t2占有這把鎖之后,進(jìn)入同步代碼塊執(zhí)行程序。
這樣就達(dá)到了線程排隊(duì)執(zhí)行
這里需要注意的是:這個共享對象一定要選好了,這個共享對象一定是你需要排隊(duì)執(zhí)行的這些線程對象所共享的。
//對象
Object obj=new Object(); //實(shí)例變量(Account對象是多線程共享的,Account對象中的實(shí)例變量obj也是共享的)
synchronized(obj){}

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)
括號里邊只要是共享對象就行。
Object obj2=new Object(); //局部變量
synchronized(obj2){}
這樣寫就不安全了,因?yàn)閛bj2是局部變量,不是共享對象。
synchronized(“abc”){}
這樣寫時可以的。存在字符串常量池中
寫"abc"的話所有線程都會同步

而如果是寫synchronized(this){}的話,我們創(chuàng)建了一個新的對象act2可不用共享對象。
所以最好是寫synchronized(this){},比如你要取款,要讓其他取別的賬戶的人也要等嗎?不應(yīng)該,只有同時對你這1個賬戶取款的時候,需要等待,別人取錢的時候,需要從其他賬戶中取錢,就不需要等待。

java中有三大變量的線程安全問題

實(shí)例變量,在堆中
靜態(tài)變量,在方法區(qū)
局部變量,在棧中

以上三大變量
局部變量永遠(yuǎn)不會存在線程安全問題
因?yàn)榫植孔兞坎还蚕恚ㄒ粋€線程一個棧)
局部變量在棧中,所以局部變量永遠(yuǎn)都不會共享
實(shí)例變量在堆中,堆只有1個。
靜態(tài)變量在方法區(qū)中,方法區(qū)只有1個
。
堆和方法區(qū)都是多線程共享的,所以可能存在線程安全問題。

局部變量+常量:不會有線程安全問題。
成員變量:可能會有線程安全問題
。

同步代碼塊越小,效率越高。

//多線程執(zhí)行這個方法//synchronized(this)//這里的this是AccountThread對象,這個對象不共享。synchronized(act){
			act.withdraw(money);
			System.out.println(Thread.currentThread().getName()+"賬戶"+act.getActno()+"取款成功,余額:"+act.getBalance());}

在實(shí)例方法上使用synchronized

在實(shí)例方法上可以使用synchronized嗎?可以的。
synchronized出現(xiàn)在實(shí)例方法上,一定鎖的是this
沒得挑,只能是this,不能是其他的對象了
所以這種方式不靈活。
另外還有一個缺點(diǎn):synchronized出現(xiàn)在實(shí)例方法上,表示整個方法體都需要同步
可能會擴(kuò)大同步的范圍,導(dǎo)致程序的執(zhí)行效率降低。所以這種方式不常用。
synchronized使用在實(shí)例方法上有什么優(yōu)點(diǎn)?
代碼寫的少了,節(jié)儉了。
如果共享的對象是this,并且需要同步的代碼是整個方法體,建議使用這種方式。
StringBuffer就是在每個方法上加了synchronized關(guān)鍵字

使用局部變量的話,最好使用StringBuilder
因?yàn)榫植孔兞坎淮嬖诰€程安全問題,選擇StringBuilder,StringBuffer效率比較低。
ArrayList是非線程安全的。
Vector是線程安全的。
HashMap HashSet是非線程安全的。
Hashtable是線程安全的
。

總結(jié)

synchronized有三種寫法:

??第一種:同步代碼塊
????靈活
??????synchronized(線程共享對象){
????????同步代碼塊;
??????}
??第二種:在實(shí)例方法上使用synchronized
??????表示共享對象一定是this
??????并且同步代碼塊是整個方法體。
??第三種:在靜態(tài)方法上使用synchronized
??????表示找類鎖。
??????類鎖永遠(yuǎn)只有1把。
??????就算創(chuàng)建了100個對象,那類鎖也只有一把。

對象鎖:1個對象1把鎖,100個對象100把鎖。
類鎖:100個對象,也可能只是1把類鎖。

面試題

//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//不需要,因?yàn)閐oother方法沒有synchronized

public?class?exam01?{
	public?static?void?main(String[]?args)?{
		MyClass?mc=new?MyClass();
		Thread?t1=new?MyThread(mc);
		Thread?t2=new?MyThread(mc);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		try?{
			Thread.sleep(1000);		//這個睡眠的作用是:為了保證t1線程先執(zhí)行
		}?catch?(InterruptedException?e)?{
			//?TODO?Auto-generated?catch?block
			e.printStackTrace();
		}
		t2.start();
	}}class?MyThread?extends?Thread{
	private?MyClass?mc;
	public?MyThread(MyClass?mc)?{
		super();
		this.mc?=?mc;
	}
	public?void?run(){
		if(Thread.currentThread().getName().equals("t1")){
			mc.dosome();
		}
		if(Thread.currentThread().getName().equals("t2")){
			mc.doOther();
		}
	}
	}class?MyClass{
	public?synchronized?void?dosome(){
		System.out.println("doSome?begin");
		try?{
			Thread.sleep(1000);
		}?catch?(InterruptedException?e)?{
			//?TODO?Auto-generated?catch?block
			e.printStackTrace();
		}
		System.out.println("doSome?end");
	}
	public?void?doOther(){
		System.out.println("doOther?begin");
		System.out.println("doOther?end");
	}}

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)
當(dāng)在doother上面加了synchronized呢
//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//需要,因?yàn)閐oother方法沒有synchronized

	public?synchronized?void?doOther(){
		System.out.println("doOther?begin");
		System.out.println("doOther?end");
	}

//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//不用排隊(duì),誰也不用管誰

MyClass?mc1=new?MyClass();MyClass?mc2=new?MyClass();Thread?t1=new?MyThread(mc1);Thread?t2=new?MyThread(mc2);

//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//需要,因?yàn)殪o態(tài)方法是類鎖,類鎖不管創(chuàng)建了幾個對象,類鎖只有一把

MyClass?mc1=new?MyClass();MyClass?mc2=new?MyClass();Thread?t1=new?MyThread(mc1);Thread?t2=new?MyThread(mc2);public?synchronized?static?void?dosome(){
		System.out.println("doSome?begin");
		try?{
			Thread.sleep(1000);
		}?catch?(InterruptedException?e)?{
			//?TODO?Auto-generated?catch?block
			e.printStackTrace();
		}
		System.out.println("doSome?end");
	}
	public?synchronized?static?void?doOther(){
		System.out.println("doOther?begin");
		System.out.println("doOther?end");
	}

這種鎖叫排他鎖:

4.死鎖

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)
synchronized在開發(fā)中最好不要嵌套使用,一不小心就可能導(dǎo)致死鎖。
死鎖代碼要會寫。
一般面試官要求你會寫
只有會寫的,才會在以后的開發(fā)中注意這個事兒
因?yàn)樗梨i很難調(diào)試。

public?class?DeadLock?{
	public?static?void?main(String[]?args)?{
		Object?o1=new?Object();
		Object?o2=new?Object();
		//t1線程和t2線程共享o1,o2
		Thread?t1=new?MyThread1(o1,o2);
		Thread?t2=new?MyThread2(o1,o2);
		t1.start();
		t2.start();
	}}class?MyThread1?extends?Thread{
	Object?o1;
	Object?o2;
	public?MyThread1(Object?o1,Object?o2){
		this.o1=o1;
		this.o2=o2;
	}
	@Override
	public?void?run()?{
		synchronized?(o1)?{
			try?{
				Thread.sleep(1000);
			}?catch?(InterruptedException?e)?{
				//?TODO?Auto-generated?catch?block
				e.printStackTrace();
			}
			synchronized?(o2)?{
				
			}
		}
	}}class?MyThread2?extends?Thread{
	Object?o1;
	Object?o2;
	public?MyThread2(Object?o1,Object?o2){
		this.o1=o1;
		this.o2=o2;
	}
	@Override
	public?void?run()?{
		synchronized?(o2)?{
			try?{
				Thread.sleep(1000);
			}?catch?(InterruptedException?e)?{
				//?TODO?Auto-generated?catch?block
				e.printStackTrace();
			}
			synchronized?(o1)?{
				
			}
		}
	}}

5.開發(fā)中應(yīng)該怎么解決線程安全問題

聊一聊,我們以后開發(fā)中應(yīng)該怎么解決線程安全問題?
??是一上來就選擇線程同步嗎?synchronized
??不是,synchronized會讓程序的執(zhí)行效率降低,用戶體驗(yàn)不好。
??系統(tǒng)的用戶吞吐量降低。用戶體驗(yàn)差。在不得已的情況下再選擇
??線程同步機(jī)制。
??第一種方案:盡量使用局部變量代替“實(shí)例變量和靜態(tài)變量”。
??第二種方案:如果必須是實(shí)例變量,那么可以考慮創(chuàng)建多個對象,這樣實(shí)例變量的內(nèi)存就不共享了。(一個線程對應(yīng)1個對象,100個線程對應(yīng)100個對象,對象不共享,就沒有數(shù)據(jù)安全問題了。)
??第三種方案:如果不能使用局部變量,對象也不能創(chuàng)建多個,這個時候就只能選擇synchronized了。線程同步機(jī)制。
線程這塊還有那些內(nèi)容呢?列舉一下
7.1、守護(hù)線程
7.2、定時器
7.3、實(shí)現(xiàn)線程的第三種方式:FutureTask方式,實(shí)現(xiàn)Callable接口。(JDK8新特性。)
7.4、關(guān)于Object類中的wait和notify方法。(生產(chǎn)者和消費(fèi)者模式?。?/p>

6.守護(hù)線程

守護(hù)線程
java語言中線程分為兩大類:
??一類是:用戶線程
??一類是:守護(hù)線程(后臺線程)

其中具有代表性的就是:垃圾回收線程(守護(hù)線程)。
??守護(hù)線程的特點(diǎn):
??一般守護(hù)線程是一個死循環(huán),所有的用戶線程只要結(jié)束,
??守護(hù)線程自動結(jié)束。
??注意:主線程main方法是一個用戶線程。
??守護(hù)線程用在什么地方呢?
??每天00:00的時候系統(tǒng)數(shù)據(jù)自動備份。
??這個需要使用到定時器,并且我們可以將定時器設(shè)置為守護(hù)線程。
??一直在那里看著,沒到00:00的時候就備份一次。所有的用戶線程如果結(jié)束了,守護(hù)線程自動退出,沒有必要進(jìn)行數(shù)據(jù)備份了。

package?testThread;/*
實(shí)現(xiàn)守護(hù)線程
?*?*/
	public?class?ThreadTest13?{

	public?static?void?main(String[]?args)?{
		//?TODO?Auto-generated?method?stub
		Thread?t=new?BakDataThread();
		t.setName("備份數(shù)據(jù)的線程");
		//啟動之前,將線程設(shè)置為守護(hù)線程
		t.setDaemon(true);
		t.start();
		//主線程:主線程是用戶線程
		for(int?i=0;i"+i);
			try?{
				Thread.sleep(1000);
			}?catch?(Exception?e)?{
				//?TODO:?handle?exception
			}
		}
	}}class?BakDataThread?extends?Thread{
	@Override
	public?void?run()?{
		int?i=0;
		//即使是死循環(huán),但由于該線程是守護(hù)者,當(dāng)用戶線程結(jié)束,守護(hù)線程自動終止
		while(true){
			System.out.println(Thread.currentThread().getName()+"---->"+(++i));
			try?{
				Thread.sleep(1000);
			}?catch?(Exception?e)?{
				//?TODO:?handle?exception
			}
			
		}
	}}

7.定時器

定時器的作用:
??間隔特定的時間,執(zhí)行特定的程序。
??每周要進(jìn)行銀行賬戶的總賬操作。
??每天要進(jìn)行數(shù)據(jù)的備份操作。
??在實(shí)際的開發(fā)中,每隔多久執(zhí)行一段特定的程序,這種需求是很常見的,
那么在java中其實(shí)可以采用多種方式實(shí)現(xiàn):
??可以使用sleep方法,睡眠,設(shè)置睡眠時間,沒到這個時間點(diǎn)醒來,執(zhí)行任務(wù)。這種方式是最原始的定時器。(比較low)
??在java的類庫中已經(jīng)寫好了一個定時器:java.util.Timer,可以直接拿來用。不過,這種方式在目前的開發(fā)中也很少用,因?yàn)楝F(xiàn)在有很多高級框架都是支持定時任務(wù)的。

??在實(shí)際的開發(fā)中,目前使用較多的是Spring框架中提供的SpringTask框架,這個框架只要進(jìn)行簡單的配置,就可以完成定時器的任務(wù)。

8.實(shí)現(xiàn)線程的第三種方式:實(shí)現(xiàn)Callable接口

實(shí)現(xiàn)線程的第三種方式:實(shí)現(xiàn)Callable接口。(JDK8新特性。)
這種方式實(shí)現(xiàn)的線程可以獲取線程的返回值。
之前講解的那兩種方式是無法獲取線程返回值的,因?yàn)閞un方法返回void。
思考:
系統(tǒng)委派一個線程去執(zhí)行一個任務(wù),該線程執(zhí)行完任務(wù)之后,可能會有一個執(zhí)行結(jié)果,我們怎么能拿到這個執(zhí)行結(jié)果呢?
使用第三種方式:實(shí)現(xiàn)Callable接口方式

public?class?ThreadTest14?{
	public?static?void?main(String[]?args)?throws?Exception,?ExecutionException?{
		//第一步:創(chuàng)建一個未來任務(wù)類對象
		//參數(shù)非常重要,需要給一個callable接口的實(shí)現(xiàn)類對象
		FutureTask?task=new?FutureTask(new?Callable(){
			@Override
			//call方法相當(dāng)于是run方法,只不過這個有返回值,線程執(zhí)行一個任務(wù),執(zhí)行之后可能會有一個執(zhí)行結(jié)果。
			public?Object?call()?throws?Exception?{
				System.out.println("call?method?begin");
				Thread.sleep(1000);
				System.out.println("call?method?begin");
				int?a=100;
				int?b=200;
				return?a+b;			//自動裝箱
			}		
		});
		//創(chuàng)建線程對象
		Thread?t=new?Thread(task);
		
		//啟動線程
		t.start();
		
		//這里是main方法,這是在主線程中
		//在線程中,怎么獲取t線程的執(zhí)行結(jié)果
		//get方法的執(zhí)行會導(dǎo)致當(dāng)前線程阻塞
		Object?obj=task.get();
		System.out.println("線程執(zhí)行結(jié)果"+obj);
		//main方法這里的程序要想執(zhí)行必須等待get()方法的結(jié)束
		//而get方法可能需要很久。因?yàn)間et()方法是為了拿另一個線程的執(zhí)行結(jié)果。
		//另一個線程的執(zhí)行是需要時間的
		System.out.println("hello,world");
	}}

這種方式的優(yōu)點(diǎn):可以獲取到線程的執(zhí)行結(jié)果
這種方式的缺點(diǎn):效率比較低,在獲取t線程執(zhí)行結(jié)果的時候,當(dāng)前線程受阻塞,效率較低。

9.Object類中的wait和notify方法

(生產(chǎn)者和消費(fèi)者模式?。?br>??第一:wait和notify方法不是線程對象的方法,是java中任何一個java對象都有的方法,因?yàn)檫@兩個方式是Object類中自帶的。
??wait方法和notify方法不是通過線程對象調(diào)用,

??不是這樣的:t.wait(),也不是這樣的:t.notify()…不對。
??第二:wait()方法作用?
????Object o = new Object();
????o.wait();
??表示:
??讓正在o對象上活動的線程進(jìn)入等待狀態(tài),無期限等待,直到被喚醒為止。
??o.wait();方法的調(diào)用,會讓“當(dāng)前線程(正在o對象上活動的線程)”進(jìn)入等待狀態(tài)。
??第三:notify()方法作用?
????Object o = new Object();
????o.notify();
??表示:
??喚醒正在o對象上等待的線程。
??還有一個notifyAll()方法:
??這個方法是喚醒o對象上處于等待的所有線程。

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)

10.生產(chǎn)者和消費(fèi)者

Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)
1.使用wait方法和notify方法實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者模式
2.什么是生產(chǎn)者和消費(fèi)者模式?
生產(chǎn)線程負(fù)責(zé)生產(chǎn),消費(fèi)線程負(fù)責(zé)消費(fèi)
生產(chǎn)線程和消費(fèi)線程要達(dá)到均衡
這是一種特殊的業(yè)務(wù)需求,在這種特殊的情況下需要使用wait方法和notify方法
3.wait和notify方法不是線程對象的方法,是普通java對象都有的方法
4.wait方法和notify方法是建立在線程同步的基礎(chǔ)之上。因?yàn)槎嗑€程要同時操作一個倉庫,有線程安全問題
5.wait方法作用:o.wait()讓正在o對象上活動的線程t進(jìn)入等待狀態(tài),并且釋放掉t線程之前占有的o對象的鎖
6.notify方法的作用:o.notify()讓正在o對象上等待的線程喚醒,只是5通知,不會釋放o對象上之前占有的鎖
7.模擬這樣一個需求:
倉庫我們采用list集合
list集合中假設(shè)只能存儲1個元素
1個元素就表示倉庫滿了
如果list集合中的元素個數(shù)是0,就表示倉庫空了。
保證list集合中永遠(yuǎn)都是最多存儲1個元素
必須做到這種效果,生產(chǎn)1個消費(fèi)1個。

public?class?ThreadTest15?{
	public?static?void?main(String[]?args)?{
		//創(chuàng)建一個倉庫獨(dú)享,共享的
		List?list=new?ArrayList();
		//創(chuàng)建兩個線程對象
		//生產(chǎn)者線程
		Thread?t1=new?Thread(new?Producer(list));
		//消費(fèi)者線程
		Thread?t2=new?Thread(new?Consumer(list));
		t1.setName("生產(chǎn)者線程");
		t2.setName("消費(fèi)者線程");
		t1.start();
		t2.start();
	}}//生產(chǎn)線程class?Producer?implements?Runnable{
	//倉庫
	private?List?list;
	public?Producer(List?list)?{
		this.list?=?list;
	}
	public?void?run()?{
		//一直生產(chǎn)
		while(true){
			//給倉庫對象list加鎖
			synchronized?(list)?{
				if(list.size()>0){	//大于0說明倉庫中已經(jīng)有1個元素了
					//當(dāng)前線程進(jìn)入等待狀態(tài),并且釋放list集合的鎖
					try?{
						list.wait();
					}?catch?(InterruptedException?e)?{
						//?TODO?Auto-generated?catch?block
						e.printStackTrace();
					}
				}
				//程序能夠執(zhí)行到這里說明倉庫是空的,可以生產(chǎn)
				Object?obj?=new?Object();
				list.add(obj);
				System.out.println(Thread.currentThread().getName()+"---->"+obj);
				//喚醒消費(fèi)者進(jìn)行消費(fèi)
				list.notifyAll();
			}
			
		}
	}}//消費(fèi)線程class?Consumer?implements?Runnable{
	//倉庫
	private?List?list;
	public?Consumer(List?list)?{
		this.list?=?list;
	}
	public?void?run()?{
		//一直消費(fèi)
		while(true){
			//給倉庫對象list加鎖
			synchronized?(list)?{
				if(list.size()==0){	//倉里已經(jīng)空了
					try?{
						//倉庫已經(jīng)空了
						//消費(fèi)者線程等待,并釋放掉list集合鎖
						list.wait();
					}?catch?(InterruptedException?e)?{
						//?TODO?Auto-generated?catch?block
						e.printStackTrace();
					}
				}
			}
			Object?obj=list.remove(0);
			System.out.println(Thread.currentThread().getName()+"---->"+obj);
			//喚醒生產(chǎn)者生產(chǎn)
			list.notifyAll();
		}
	}}

相關(guān)學(xué)習(xí)推薦:java基礎(chǔ)

以上是Java並發(fā)程式設(shè)計(jì)之介紹線程安全基礎(chǔ)的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1600
29
PHP教程
1502
276
如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務(wù),必須先關(guān)閉自動提交模式,再執(zhí)行多個操作,最後根據(jù)結(jié)果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開始事務(wù);2.執(zhí)行多個SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時應(yīng)使用try-with-resources管理資源,妥善處理異常並關(guān)閉連接,避免連接洩漏;此外建議使用連接池、設(shè)置保存點(diǎn)實(shí)現(xiàn)部分回滾,並保持事務(wù)盡可能短以提升性能。

如何使用Java的日曆? 如何使用Java的日曆? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過LocalDate、LocalDateTime和LocalTime獲取當(dāng)前日期時間;3.使用of()方法創(chuàng)建特定日期時間;4.利用plus/minus方法不可變地增減時間;5.使用ZonedDateTime和ZoneId處理時區(qū);6.通過DateTimeFormatter格式化和解析日期字符串;7.必要時通過Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應(yīng)優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

比較Java框架:Spring Boot vs Quarkus vs Micronaut 比較Java框架:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

前形式攝取,quarkusandmicronautleaddueTocile timeProcessingandGraalvSupport,withquarkusoftenpernperforminglightbetterine nosserless notelless centarios.2。

垃圾收集如何在Java工作? 垃圾收集如何在Java工作? Aug 02, 2025 pm 01:55 PM

Java的垃圾回收(GC)是自動管理內(nèi)存的機(jī)制,通過回收不可達(dá)對象釋放堆內(nèi)存,減少內(nèi)存洩漏風(fēng)險(xiǎn)。 1.GC從根對象(如棧變量、活動線程、靜態(tài)字段等)出發(fā)判斷對象可達(dá)性,無法到達(dá)的對像被標(biāo)記為垃圾。 2.基於標(biāo)記-清除算法,標(biāo)記所有可達(dá)對象,清除未標(biāo)記對象。 3.採用分代收集策略:新生代(Eden、S0、S1)頻繁執(zhí)行MinorGC;老年代執(zhí)行較少但耗時較長的MajorGC;Metaspace存儲類元數(shù)據(jù)。 4.JVM提供多種GC器:SerialGC適用於小型應(yīng)用;ParallelGC提升吞吐量;CMS降

了解網(wǎng)絡(luò)端口和防火牆 了解網(wǎng)絡(luò)端口和防火牆 Aug 01, 2025 am 06:40 AM

NetworkPortSandFireWallsworkTogetHertoEnableCommunication whereSeringSecurity.1.NetWorkPortSareVirtualendPointSnumbered0-655 35,with-Well-with-Newonportslike80(HTTP),443(https),22(SSH)和25(smtp)sindiessingspefificservices.2.portsoperateervertcp(可靠,c

以身作則,解釋說明 以身作則,解釋說明 Aug 02, 2025 am 06:26 AM

defer用於在函數(shù)返回前執(zhí)行指定操作,如清理資源;參數(shù)在defer時立即求值,函數(shù)按後進(jìn)先出(LIFO)順序執(zhí)行;1.多個defer按聲明逆序執(zhí)行;2.常用於文件關(guān)閉等安全清理;3.可修改命名返回值;4.即使發(fā)生panic也會執(zhí)行,適合用於recover;5.避免在循環(huán)中濫用defer,防止資源洩漏;正確使用可提升代碼安全性和可讀性。

比較Java構(gòu)建工具:Maven vs. Gradle 比較Java構(gòu)建工具:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

Java並發(fā)公用事業(yè):執(zhí)行人員服務(wù)和叉/加入 Java並發(fā)公用事業(yè):執(zhí)行人員服務(wù)和叉/加入 Aug 03, 2025 am 01:54 AM

ExecutorService適用於獨(dú)立任務(wù)的異步執(zhí)行,如I/O操作或定時任務(wù),使用線程池管理並發(fā),通過submit提交Runnable或Callable任務(wù),並用Future獲取結(jié)果,需注意無界隊(duì)列風(fēng)險(xiǎn)和顯式關(guān)閉線程池;2.Fork/Join框架專為可拆分的CPU密集型任務(wù)設(shè)計(jì),基於分治法和工作竊取算法,通過RecursiveTask或RecursiveAction實(shí)現(xiàn)任務(wù)遞歸拆分,由ForkJoinPool調(diào)度執(zhí)行,適合大數(shù)組求和、排序等場景,需合理設(shè)置拆分閾值避免開銷;3.選擇依據(jù):獨(dú)立任

See all articles