1. 被棄用的 stop、suspend 和 resume 方法
用 stop() 來(lái)停止線程,會(huì)導(dǎo)致線程運(yùn)行一半突然停止,沒(méi)辦法完成一個(gè)基本單位的操作,會(huì)造成臟數(shù)據(jù);
模擬連隊(duì)發(fā)裝備代碼示例:
public class StopThread implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("連隊(duì)" + i + " 開(kāi)始領(lǐng)取:");
for (int j = 1; j <= 10; j++) {
System.out.println("士兵" + j + " 開(kāi)始領(lǐng)取");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("====連隊(duì)" + i + "領(lǐng)取完畢====");
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new StopThread());
thread.start();
// 等待666毫秒,停止線程
Thread.sleep(666);
thread.stop();
}
}
運(yùn)行結(jié)果:
連隊(duì)1 開(kāi)始領(lǐng)?。?士兵1 開(kāi)始領(lǐng)取
士兵2 開(kāi)始領(lǐng)取
士兵3 開(kāi)始領(lǐng)取
士兵4 開(kāi)始領(lǐng)取
士兵5 開(kāi)始領(lǐng)取
士兵6 開(kāi)始領(lǐng)取
士兵7 開(kāi)始領(lǐng)取
士兵8 開(kāi)始領(lǐng)取
士兵9 開(kāi)始領(lǐng)取
士兵10 開(kāi)始領(lǐng)取
====連隊(duì)1領(lǐng)取完畢====
連隊(duì)2 開(kāi)始領(lǐng)?。?士兵1 開(kāi)始領(lǐng)取
士兵2 開(kāi)始領(lǐng)取
士兵3 開(kāi)始領(lǐng)取
Process finished with exit code 0
會(huì)發(fā)現(xiàn) 連隊(duì)2 才3個(gè)人領(lǐng)完,其他人都還沒(méi)有領(lǐng)到,線程突然就結(jié)束了,這樣就會(huì)造成數(shù)據(jù)的錯(cuò)亂!
并且這種數(shù)據(jù)的錯(cuò)亂后期難以排查!
Oracle官方文檔對(duì)于為什么Thread.stop不推薦使用的解釋
https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

suspend和resume被拋棄原因:
suspend和stop不一樣,suspend不會(huì)破壞對(duì)象,但是它會(huì)讓一個(gè)線程掛起,在恢復(fù)之前,鎖不會(huì)釋放,也就是它是帶著鎖去進(jìn)行休息的,這樣的話很容易造成死鎖。
resume
2. 用volatile設(shè)置boolean標(biāo)記位
2.1:看似可行的代碼
public class WrongWayVolatile implements Runnable {
/**
* 設(shè)置boolean類型的標(biāo)記位
*/
private volatile boolean canceled = false;
public static void main(String[] args) throws InterruptedException {
WrongWayVolatile r = new WrongWayVolatile();
Thread t = new Thread(r);
t.start();
// 等待5秒后
Thread.sleep(5000);
// 更改canceled值以達(dá)到停止程序的目的
r.canceled = true;
}
@Override
public void run() {
int num = 0;
try {
while (num <= Integer.MAX_VALUE && !canceled) {
if (num % 100 == 0) {
System.out.println(num + "是100的倍數(shù)");
}
num++;
Thread.sleep(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
程序在運(yùn)行5秒鐘后停止了,達(dá)到了預(yù)期的效果。
2.2:當(dāng)陷入阻塞時(shí),無(wú)法停止
下面代碼示例中,生產(chǎn)者的生產(chǎn)速度很快,消費(fèi)者消費(fèi)速度慢,
所以阻塞隊(duì)列滿了以后,生產(chǎn)者會(huì)阻塞停止生產(chǎn),等待消費(fèi)者進(jìn)一步消費(fèi)
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class WrongWayVolatileCantStop {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
Producer producer = new Producer(storage);
Thread producerThread = new Thread(producer);
producerThread.start();
// 等待1秒讓生產(chǎn)者將隊(duì)列填滿
Thread.sleep(1000);
Consumer consumer = new Consumer(storage);
while (consumer.needMoreNums()) {
System.out.println(consumer.storage.take() + "被消費(fèi)了!");
// 消費(fèi)是需要時(shí)間的,設(shè)置個(gè)100毫秒
Thread.sleep(100);
}
System.out.println("消費(fèi)者不需要更多數(shù)據(jù)了。");
// 一旦消費(fèi)者不需要更多數(shù)據(jù)了,則應(yīng)該讓生產(chǎn)者停下來(lái),
// 將標(biāo)記位設(shè)置為true,看是否能將線程停止?
producer.canceled = true;
System.out.println(producer.canceled);
}
}
/**
* 生產(chǎn)者
*/
class Producer implements Runnable {
/**
* 設(shè)置boolean類型的標(biāo)記位
*/
public volatile boolean canceled = false;
BlockingQueue storage;
public Producer(BlockingQueue storage) {
this.storage = storage;
}
@Override
public void run() {
int num = 0;
try {
while (num <= Integer.MAX_VALUE && !canceled) {
if (num % 100 == 0) {
storage.put(num);
System.out.println(num + "是100的倍數(shù),被放到了倉(cāng)庫(kù)中。");
}
num++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("生產(chǎn)者結(jié)束運(yùn)行");
}
}
}
/**
* 消費(fèi)者
*/
class Consumer {
BlockingQueue storage;
public Consumer(BlockingQueue storage) {
this.storage = storage;
}
public boolean needMoreNums() {
// 隨機(jī)返回true或false
if (Math.random() > 0.95) {
return false;
}
return true;
}
}
最后的運(yùn)行結(jié)果并沒(méi)有打印出 “生產(chǎn)者結(jié)束運(yùn)行”,
而且程序也沒(méi)有停止!??!

為什么?
因?yàn)樯a(chǎn)者暫停生產(chǎn)時(shí),是阻塞在 storage.put(num);
而且也沒(méi)有人去喚醒,所以 while() 條件也無(wú)法執(zhí)行,也不知道 canceled 的值已經(jīng)被改變!
只會(huì)一直等在 storage.put(num); 這里。
解決方法:使用 interrupt
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class WrongWayVolatileCantStop {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
Producer producer = new Producer(storage);
Thread producerThread = new Thread(producer);
producerThread.start();
// 等待1秒讓生產(chǎn)者將隊(duì)列填滿
Thread.sleep(1000);
Consumer consumer = new Consumer(storage);
while (consumer.needMoreNums()) {
System.out.println(consumer.storage.take() + "被消費(fèi)了!");
// 消費(fèi)是需要時(shí)間的,設(shè)置個(gè)100毫秒
Thread.sleep(100);
}
System.out.println("消費(fèi)者不需要更多數(shù)據(jù)了。");
// 一旦消費(fèi)者不需要更多數(shù)據(jù)了,則應(yīng)該讓生產(chǎn)者停下來(lái),
// 使用interrupt通知停止線程
producerThread.interrupt();
}
}
/**
* 生產(chǎn)者
*/
class Producer implements Runnable {
BlockingQueue storage;
public Producer(BlockingQueue storage) {
this.storage = storage;
}
@Override
public void run() {
int num = 0;
try {
while (num <= Integer.MAX_VALUE && !Thread.currentThread().isInterrupted()) {
if (num % 100 == 0) {
storage.put(num);
System.out.println(num + "是100的倍數(shù),被放到了倉(cāng)庫(kù)中。");
}
num++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("生產(chǎn)者結(jié)束運(yùn)行");
}
}
}
/**
* 消費(fèi)者
*/
class Consumer {
BlockingQueue storage;
public Consumer(BlockingQueue storage) {
this.storage = storage;
}
public boolean needMoreNums() {
// 隨機(jī)返回true或false
if (Math.random() > 0.95) {
return false;
}
return true;
}
}