亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁(yè) 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.線程安全問(wèn)題
    • 2.帳戶取款案例
    • 3.同步程式碼區(qū)塊synchronized
    • #synchronized的理解
    java中有三大變數(shù)的執(zhí)行緒安全性問(wèn)題
  • 在實(shí)例方法上使用synchronized
  • 總結(jié)
  • #面試題
  • 4.死鎖
  • 5.開(kāi)發(fā)中該怎麼解決執(zhí)行緒安全性問(wèn)題
  • 6.守護(hù)執(zhí)行緒
# 7.定時(shí)器

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

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


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


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

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

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

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

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

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

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

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

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

Account類別

package?ThreadSafe;public?class?Account?{
	//賬號(hào)
	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í)行這個(gè)方法(t1和t2是兩個(gè)棧?,兩個(gè)棧操作堆中同一個(gè)對(duì)象)
		//取款之前的余額
		double?before=this.getBalance();
		//取款之后的余額
		double?after=before-money;
		//模擬一下網(wǎng)絡(luò)延遲,會(huì)出現(xiàn)問(wèn)題
		try?{
			Thread.sleep(1000);
		}?catch?(InterruptedException?e)?{
			//?TODO?Auto-generated?catch?block
			e.printStackTrace();
		}
		//更新余額
		//思考:t1執(zhí)行到這里了,但還沒(méi)有來(lái)得及執(zhí)行這行代碼,t2線程進(jìn)來(lái)withdraw方法了,此時(shí)一定出問(wèn)題
		this.setBalance(after);
	}}AccountThread類public?class?AccountThread?extends?Thread{
	//兩個(gè)線程必須共享一個(gè)賬戶對(duì)象
	private?Account?act;
	//通過(guò)構(gòu)造方法傳遞過(guò)來(lái)賬戶對(duì)象
	public?AccountThread(Account?act)?{
		this.act?=?act;
	}
	@Override
	public?void?run()?{
		//假設(shè)取款5000
		double?money=5000;
		//多線程執(zhí)行這個(gè)方法
		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)建賬戶對(duì)象
		Account?act=new?Account("act-001",10000);
		//創(chuàng)建兩個(gè)線程
		Thread?t1=new?AccountThread(act);
		Thread?t2=new?AccountThread(act);
		
		t1.setName("t1");
		t2.setName("t2");
		//啟動(dòng)兩個(gè)線程執(zhí)行
		t1.start();
		t2.start();
	}}


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

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

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

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

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

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

()中寫(xiě)什麼? ### 那要看你想讓哪些線程同步### 假設(shè)t1、t2、t3、t4、t5有5個(gè)線程### 你只希望t1 t2 t3排隊(duì),t4 t5不需要排隊(duì),怎麼辦## # 你一定要在()中寫(xiě)一個(gè)t1 t2 t3共享的對(duì)象,而這個(gè)對(duì)象對(duì)於t4 t5來(lái)說(shuō)不是??共享的### 這裡的共享對(duì)像是賬戶對(duì)象### 帳戶對(duì)像是共享的,this是賬戶物件### 有時(shí)不一定是this,這裡只要是多執(zhí)行緒共享的那個(gè)物件就行###
		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語(yǔ)言中,任何對(duì)象都有一把鎖,其實(shí)這把鎖就是一個(gè)標(biāo)記,(只是把它叫做鎖)
100個(gè)對(duì)象,100個(gè)鎖,1個(gè)對(duì)象1把鎖。
以上代碼的執(zhí)行原理是什么呢?
1.假設(shè)t1和t2線程并發(fā),開(kāi)始執(zhí)行以上代碼的時(shí)候,肯定有一個(gè)先一個(gè)后,
2.假設(shè)t1先執(zhí)行了,遇到了synchronized,這個(gè)時(shí)候自動(dòng)找后面共享對(duì)象的對(duì)象鎖,找到之后,并占有這把鎖,然后執(zhí)行同步代碼塊中的程序,在程序執(zhí)行過(guò)程中一直都占有這把鎖,直到同步代碼塊執(zhí)行結(jié)束,這把鎖才會(huì)釋放。
3.假設(shè)t1已經(jīng)占有這把鎖,此時(shí)t2也遇到synchronized關(guān)鍵字,也會(huì)去占有后面共享對(duì)象的這把鎖,結(jié)果這把鎖被t1占有,t2只能在同步代碼塊外邊等待t1的結(jié)束,直到t1把同步代碼塊執(zhí)行結(jié)束了,t1會(huì)歸還這把鎖,此時(shí)t2終于等到這把鎖,然后t2占有這把鎖之后,進(jìn)入同步代碼塊執(zhí)行程序。
這樣就達(dá)到了線程排隊(duì)執(zhí)行
這里需要注意的是:這個(gè)共享對(duì)象一定要選好了,這個(gè)共享對(duì)象一定是你需要排隊(duì)執(zhí)行的這些線程對(duì)象所共享的。
//對(duì)象
Object obj=new Object(); //實(shí)例變量(Account對(duì)象是多線程共享的,Account對(duì)象中的實(shí)例變量obj也是共享的)
synchronized(obj){}

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

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

java中有三大變量的線程安全問(wèn)題

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

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

局部變量+常量:不會(huì)有線程安全問(wèn)題。
成員變量:可能會(huì)有線程安全問(wèn)題
。

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

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

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

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

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

總結(jié)

synchronized有三種寫(xiě)法:

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

對(duì)象鎖:1個(gè)對(duì)象1把鎖,100個(gè)對(duì)象100把鎖。
類鎖:100個(gè)對(duì)象,也可能只是1把類鎖。

面試題

//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//不需要,因?yàn)閐oother方法沒(méi)有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);		//這個(gè)睡眠的作用是:為了保證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方法沒(méi)有synchronized

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

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

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)建了幾個(gè)對(duì)象,類鎖只有一把

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在開(kāi)發(fā)中最好不要嵌套使用,一不小心就可能導(dǎo)致死鎖。
死鎖代碼要會(huì)寫(xiě)。
一般面試官要求你會(huì)寫(xiě)
只有會(huì)寫(xiě)的,才會(huì)在以后的開(kāi)發(fā)中注意這個(gè)事兒
因?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.開(kāi)發(fā)中應(yīng)該怎么解決線程安全問(wèn)題

聊一聊,我們以后開(kāi)發(fā)中應(yīng)該怎么解決線程安全問(wèn)題?
??是一上來(lái)就選擇線程同步嗎?synchronized
??不是,synchronized會(huì)讓程序的執(zhí)行效率降低,用戶體驗(yàn)不好。
??系統(tǒng)的用戶吞吐量降低。用戶體驗(yàn)差。在不得已的情況下再選擇
??線程同步機(jī)制。
??第一種方案:盡量使用局部變量代替“實(shí)例變量和靜態(tài)變量”。
??第二種方案:如果必須是實(shí)例變量,那么可以考慮創(chuàng)建多個(gè)對(duì)象,這樣實(shí)例變量的內(nèi)存就不共享了。(一個(gè)線程對(duì)應(yīng)1個(gè)對(duì)象,100個(gè)線程對(duì)應(yīng)100個(gè)對(duì)象,對(duì)象不共享,就沒(méi)有數(shù)據(jù)安全問(wèn)題了。)
??第三種方案:如果不能使用局部變量,對(duì)象也不能創(chuàng)建多個(gè),這個(gè)時(shí)候就只能選擇synchronized了。線程同步機(jī)制
線程這塊還有那些內(nèi)容呢?列舉一下
7.1、守護(hù)線程
7.2、定時(shí)器
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語(yǔ)言中線程分為兩大類:
??一類是:用戶線程
??一類是:守護(hù)線程(后臺(tái)線程)

其中具有代表性的就是:垃圾回收線程(守護(hù)線程)。
??守護(hù)線程的特點(diǎn):
??一般守護(hù)線程是一個(gè)死循環(huán),所有的用戶線程只要結(jié)束,
??守護(hù)線程自動(dòng)結(jié)束。
??注意:主線程main方法是一個(gè)用戶線程。
??守護(hù)線程用在什么地方呢?
??每天00:00的時(shí)候系統(tǒng)數(shù)據(jù)自動(dòng)備份。
??這個(gè)需要使用到定時(shí)器,并且我們可以將定時(shí)器設(shè)置為守護(hù)線程。
??一直在那里看著,沒(méi)到00:00的時(shí)候就備份一次。所有的用戶線程如果結(jié)束了,守護(hù)線程自動(dòng)退出,沒(méi)有必要進(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ù)的線程");
		//啟動(dòng)之前,將線程設(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ù)線程自動(dòng)終止
		while(true){
			System.out.println(Thread.currentThread().getName()+"---->"+(++i));
			try?{
				Thread.sleep(1000);
			}?catch?(Exception?e)?{
				//?TODO:?handle?exception
			}
			
		}
	}}

7.定時(shí)器

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

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

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

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

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

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

9.Object類中的wait和notify方法

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

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

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方法不是線程對(duì)象的方法,是普通java對(duì)象都有的方法
4.wait方法和notify方法是建立在線程同步的基礎(chǔ)之上。因?yàn)槎嗑€程要同時(shí)操作一個(gè)倉(cāng)庫(kù),有線程安全問(wèn)題
5.wait方法作用:o.wait()讓正在o對(duì)象上活動(dòng)的線程t進(jìn)入等待狀態(tài),并且釋放掉t線程之前占有的o對(duì)象的鎖
6.notify方法的作用:o.notify()讓正在o對(duì)象上等待的線程喚醒,只是5通知,不會(huì)釋放o對(duì)象上之前占有的鎖
7.模擬這樣一個(gè)需求:
倉(cāng)庫(kù)我們采用list集合
list集合中假設(shè)只能存儲(chǔ)1個(gè)元素
1個(gè)元素就表示倉(cāng)庫(kù)滿了
如果list集合中的元素個(gè)數(shù)是0,就表示倉(cāng)庫(kù)空了。
保證list集合中永遠(yuǎn)都是最多存儲(chǔ)1個(gè)元素
必須做到這種效果,生產(chǎn)1個(gè)消費(fèi)1個(gè)。

public?class?ThreadTest15?{
	public?static?void?main(String[]?args)?{
		//創(chuàng)建一個(gè)倉(cāng)庫(kù)獨(dú)享,共享的
		List?list=new?ArrayList();
		//創(chuàng)建兩個(gè)線程對(duì)象
		//生產(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{
	//倉(cāng)庫(kù)
	private?List?list;
	public?Producer(List?list)?{
		this.list?=?list;
	}
	public?void?run()?{
		//一直生產(chǎn)
		while(true){
			//給倉(cāng)庫(kù)對(duì)象list加鎖
			synchronized?(list)?{
				if(list.size()>0){	//大于0說(shuō)明倉(cāng)庫(kù)中已經(jīng)有1個(gè)元素了
					//當(dāng)前線程進(jìn)入等待狀態(tài),并且釋放list集合的鎖
					try?{
						list.wait();
					}?catch?(InterruptedException?e)?{
						//?TODO?Auto-generated?catch?block
						e.printStackTrace();
					}
				}
				//程序能夠執(zhí)行到這里說(shuō)明倉(cāng)庫(kù)是空的,可以生產(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{
	//倉(cāng)庫(kù)
	private?List?list;
	public?Consumer(List?list)?{
		this.list?=?list;
	}
	public?void?run()?{
		//一直消費(fèi)
		while(true){
			//給倉(cāng)庫(kù)對(duì)象list加鎖
			synchronized?(list)?{
				if(list.size()==0){	//倉(cāng)里已經(jīng)空了
					try?{
						//倉(cāng)庫(kù)已經(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)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

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

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(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整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72
VSCODE設(shè)置。 JSON位置 VSCODE設(shè)置。 JSON位置 Aug 01, 2025 am 06:12 AM

settings.json文件位於用戶級(jí)或工作區(qū)級(jí)路徑,用於自定義VSCode設(shè)置。 1.用戶級(jí)路徑:Windows為C:\Users\\AppData\Roaming\Code\User\settings.json,macOS為/Users//Library/ApplicationSupport/Code/User/settings.json,Linux為/home//.config/Code/User/settings.json;2.工作區(qū)級(jí)路徑:項(xiàng)目根目錄下的.vscode/settings

Python Itertools組合示例 Python Itertools組合示例 Jul 31, 2025 am 09:53 AM

itertools.combinations用於生成從可迭代對(duì)像中選取指定數(shù)量元素的所有不重複組合(順序無(wú)關(guān)),其用法包括:1.從列表中選2個(gè)元素組合,如('A','B')、('A','C')等,避免重複順序;2.對(duì)字符串取3個(gè)字符組合,如"abc"、"abd",適用於子序列生成;3.求兩數(shù)之和等於目標(biāo)值的組合,如1 5=6,簡(jiǎn)化雙重循環(huán)邏輯;組合與排列的區(qū)別在於順序是否重要,combinations視AB與BA為相同,而permutations視為不同;

如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

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

在Java的掌握依賴注入春季和Guice 在Java的掌握依賴注入春季和Guice Aug 01, 2025 am 05:53 AM

依賴性(di)IsadesignpatternwhereObjectsReceivedenciesenciesExtern上,推廣looseSecouplingAndEaseerTestingThroughConstructor,setter,orfieldInjection.2.springfraMefringframeWorkSannotationsLikeLikeLike@component@component,@component,@service,@autowiredwithjava-service和@autowiredwithjava-ligatiredwithjava-lase-lightike

Python Pytest夾具示例 Python Pytest夾具示例 Jul 31, 2025 am 09:35 AM

fixture是用於為測(cè)試提供預(yù)設(shè)環(huán)境或數(shù)據(jù)的函數(shù),1.使用@pytest.fixture裝飾器定義fixture;2.在測(cè)試函數(shù)中以參數(shù)形式註入fixture;3.yield之前執(zhí)行setup,之後執(zhí)行teardown;4.通過(guò)scope參數(shù)控製作用域,如function、module等;5.將共用fixture放在conftest.py中實(shí)現(xiàn)跨文件共享,從而提升測(cè)試的可維護(hù)性和復(fù)用性。

故障排除常見(jiàn)的java`ofmemoryError`場(chǎng)景'' 故障排除常見(jiàn)的java`ofmemoryError`場(chǎng)景'' Jul 31, 2025 am 09:07 AM

java.lang.OutOfMemoryError:Javaheapspace表示堆內(nèi)存不足,需檢查大對(duì)象處理、內(nèi)存洩漏及堆設(shè)置,通過(guò)堆轉(zhuǎn)儲(chǔ)分析工具定位並優(yōu)化代碼;2.Metaspace錯(cuò)誤因類元數(shù)據(jù)過(guò)多,常見(jiàn)於動(dòng)態(tài)類生成或熱部署,應(yīng)限制MaxMetaspaceSize並優(yōu)化類加載;3.Unabletocreatenewnativethread因係統(tǒng)線程資源耗盡,需檢查線程數(shù)限制、使用線程池、調(diào)整棧大?。?.GCoverheadlimitexceeded指GC頻繁但回收少,應(yīng)分析GC日誌,優(yōu)化

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

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

Java開(kāi)發(fā)人員的高級(jí)春季數(shù)據(jù)JPA Java開(kāi)發(fā)人員的高級(jí)春季數(shù)據(jù)JPA Jul 31, 2025 am 07:54 AM

掌握AdvancedSpringDataJPA的核心在於根據(jù)場(chǎng)景選擇合適的數(shù)據(jù)訪問(wèn)方式,並確保性能與可維護(hù)性。 1.自定義查詢中,@Query支持JPQL和原生SQL,適用於復(fù)雜關(guān)聯(lián)與聚合操作,返回結(jié)果建議通過(guò)DTO或接口投影(Projection)進(jìn)行類型安全映射,避免使用Object[]帶來(lái)的維護(hù)難題。 2.分頁(yè)操作需結(jié)合Pageable實(shí)現(xiàn),但要警惕N 1查詢問(wèn)題,可通過(guò)JOINFETCH預(yù)加載關(guān)聯(lián)數(shù)據(jù)或使用投影減少實(shí)體加載,從而提升性能。 3.對(duì)於多條件動(dòng)態(tài)查詢,應(yīng)使用JpaSpecifica

See all articles