java线程中stop()_Java中的線程Thread方法之---stop()

搞過Java線程的人都知道,stop這個方法是臭名昭著了,早就被棄用了,但是現在任然有很多鍾情與他的人,永遠都放不下他,因為從他的字面意思上我們可以知道他貌似可以停止一個線程,這個需求是每個搞線程開發的人都想要的操作,但是他並非是真正意義上的停止線程,而且停止線程還會引來一些其他的麻煩事,下面就來詳細的介紹一下這個方法的歷史:

從SUN的官方文檔可以得知,調用Thread.stop()方法是不安全的,這是因為當調用Thread.stop()方法時,會發生下面兩件事:

1. 即刻拋出ThreadDeath異常,在線程的run()方法內,任何一點都有可能拋出ThreadDeath Error,包括在catch或finally語句中。

2. 會釋放該線程所持有的所有的鎖,而這種釋放是不可控制的,非預期的。

當線程拋出ThreadDeath異常時,會導致該線程的run()方法突然返回來達到停止該線程的目的。ThreadDetath異常可以在該線程run()方法的任意一個執行點拋出。但是,線程的stop()方法一經調用線程的run()方法就會即刻返回嗎?

packagecom.threadstop.demo;

publicclassThreadStopTest {

publicstaticvoidmain(String[] args) {

try{

Thread t = newThread() {

//對於方法進行了同步操作,鎖對象就是線程本身

publicsynchronizedvoidrun() {

try{

longstart=System.currentTimeMillis();

//開始計數

for(inti =0; i <100000; i++)

System.out.println("runing.."+ i);

System.out.println((System.currentTimeMillis()-start)+"ms");

} catch(Throwable ex) {

System.out.println("Caught in run: "+ ex);

ex.printStackTrace();

}

}

};

//開始計數

t.start();

//主線程休眠100ms

Thread.sleep(100);

//停止線程的運行

t.stop();

} catch(Throwable t) {

System.out.println("Caught in main: "+ t);

t.printStackTrace();

}

}

}

運行結果如下:

0f0030abd6cc52162d24d20d5608880d.jpe

由於打印的數據太多了,就沒有全部截圖了,但是我們可以看到,調用了stop方法之后,線程並沒有停止,而是將run方法執行完。那這個就詭異了,多次運行之后發現每次運行的結果都表明,工作線程並沒有停止,而是每次都成功的數完數(執行完run方法),然后正常中止,而不是由stop()方法進行終止的。這個是為什么呢?根據SUN的文檔,原則上只要一調用thread.stop()方法,那么線程就會立即停止,並拋出ThreadDeath error,查看了Thread的源代碼后才發現,原先Thread.stop(Throwable obj)方法是同步的,而我們工作線程的run()方法也是同步,那么這樣會導致主線程和工作線程共同爭用同一個鎖(工作線程對象本身),由於工作線程在啟動后就先獲得了鎖,所以無論如何,當主線程在調用t.stop()時,它必須要等到工作線程的run()方法執行結束后才能進行,結果導致了上述奇怪的現象。

下面看一下stop的源碼:

@Deprecated

publicfinalvoidstop() {

stop(newThreadDeath());

}

再進到stop看:

@Deprecated

publicfinalsynchronizedvoidstop(Throwable obj) {

if(obj ==null)

thrownewNullPointerException();

SecurityManager security = System.getSecurityManager();

if(security !=null) {

checkAccess();

if((this!= Thread.currentThread()) ||

(!(obj instanceofThreadDeath))) {

security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);

}

}

// A zero status value corresponds to "NEW", it can't change to

// not-NEW because we hold the lock.

if(threadStatus !=0) {

resume(); // Wake up thread if it was suspended; no-op otherwise

}

// The VM can handle all thread states

stop0(obj);

}

stop0(obj)是一個native方法,我們看到stop方法是同步的,而這個同步的鎖對象正好也是線程本身,所以造成上面的現象。

把上述工作線程的run()方法的同步去掉,再進行執行,結果就如上述第一點描述的那樣了,運行結果如下:

d62e80c7ec8d7004f95134882accf183.jpe

從結果中我們可以看到,調用stop方法會拋出一個ThreadDeath異常,這時候run方法也就執行結束了,線程就終止了,這種是用拋異常來結束線程的,但是這種拋出線程是不安全的,因為他不可控制,不知道到在run方法中的何處就可能拋出異常,所以是危險的。下面在看一下stop的這個隱患可能造成的影響:

接下來是看看當調用thread.stop()時,被停止的線程會不會釋放其所持有的鎖,看如下代碼:

publicstaticvoidmain(String[] args) {

  //定義鎖對象

finalObject lock =newObject();

//定義第一個線程,首先該線程拿到鎖,而后等待3s,之后釋放鎖

try{

Thread t0 = newThread() {

publicvoidrun() {

try{

synchronized(lock) {

System.out.println("thread->"+ getName()  +" acquire lock.");

sleep(3*1000);

System.out.println("thread->"+ getName() +" 等待3s");

System.out.println("thread->"+ getName()  +" release lock.");

}

} catch(Throwable ex) {

System.out.println("Caught in run: "+ ex);

ex.printStackTrace();

}

}

};

//定義第二個線程,等待拿到鎖對象

Thread t1 = newThread() {

publicvoidrun() {

synchronized(lock) {

System.out.println("thread->"+ getName()  +" acquire lock.");

}

}

};

//線程一先運行,先拿到lock

t0.start();

//而后主線程等待100ms,為了做延遲

Thread.sleep(100);

//停止線程一

//t0.stop();

//這時候在開啟線程二

t1.start();

} catch(Throwable t) {

System.out.println("Caught in main: "+ t);

t.printStackTrace();

}

}

運行結果如下:

8d16b6bc50ecb42be5bddfc8c9c9c379.jpe

從運行結果中我們可以看到,當沒有進行t0.stop()方法的調用時, 可以發現,兩個線程爭用鎖的順序是固定的。這個現象是正常的。

下面我們把t0.stop注釋的哪行,刪除注釋,調用t0.stop()方法,運行結果如下:

1d051d602e3df3a784f972eb0b5f5e72.jpe

從運行結果中我們可以看到,調用了t0.stop()方法后,可以發現,t0線程拋出了ThreadDeath error並且t0線程釋放了它所占有的鎖。

從上面的程序驗證結果來看,thread.stop()確實是不安全的。它的不安全主要是:釋放該線程所持有的所有的鎖。一般任何進行加鎖的代碼塊,都是為了保護數據的一致性,如果在調用thread.stop()后導致了該線程所持有的所有鎖的突然釋放(不可控制),那么被保護數據就有可能呈現不一致性,其他線程在使用這些被破壞的數據時,有可能導致一些很奇怪的應用程序錯誤。

下面順便說一下:

Java中多線程鎖釋放的條件:

1)執行完同步代碼塊,就會釋放鎖。(synchronized)

2)在執行同步代碼塊的過程中,遇到異常而導致線程終止,鎖也會被釋放。(exception)

3)在執行同步代碼塊的過程中,執行了鎖所屬對象的wait()方法,這個線程會釋放鎖,進入對象的等待池。(wait)

從上面的三點我就可以看到stop方法釋放鎖是在第二點的,通過拋出異常來釋放鎖,通過證明,這種方式是不安全的,不可靠的。

好吧,Thread中的stop方法就說到這里了,后續還會有關Thread中的一些方法的詳解,一定要關注奧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值