啓動線程
1.Runnable是Thread執行的邏輯
2.CallableFutureTask也是Thread要執行的邏輯,只是封裝了獲取結果的功能
因此: 啓動線程的方式只有一種: new Thread().start();
終止線程
1.stop(不建議使用)
示例代碼:
public class Demo_Stop {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
// 休眠1秒,確保i變量自增成功
Thread.sleep(1000);
thread.stop();
// 確保線程已經終止
while (thread.isAlive()) {}
// 輸出結果
thread.print();
}
}
class MyThread extends Thread {
private int i = 0, j = 0;
@Override
public void run() {
synchronized (this) {
++i;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
++j;
}
System.out.println("鎖釋放。。。");
}
public void print() {
System.out.println("i=" + i + " j=" + j);
}
}
打印結果:
需要的輸出結果應該是i=0 j=0;
stop方法沒有保證同步代碼看塊中的數據一致性, 出現了線程安全問題
2.interrupt
示例代碼:
public static void main(String[] args) throws InterruptedException {
Thread workThread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("運行中");
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
//將擦除掉的isInterrupted狀態補上
Thread.currentThread().interrupt();
}
}
}
});
workThread.start();
Thread.sleep(3000L);
workThread.interrupt();
}
注意點:
1.interrupt方法並不會中斷線程,只是打上了中斷標記
示例代碼:
public static void main(String[] args) throws InterruptedException {
//開啓一個線程
Thread testThread = new Thread(){
@Override
public void run() {
while(true){
System.out.println("isInterrupted:" + Thread.currentThread().isInterrupted());
System.out.println("state:" + Thread.currentThread().getState());
}
}
};
testThread.start();
Thread.sleep(2000);
//調用interrupt方法,不會改變線程狀態
//並不會讓線程退出,只是做了一個interrupt標記
testThread.interrupt();
}
輸出結果:
可以看到,在sleep2秒後,isInterrupted的狀態值由false變爲了true
2.如果該線程在調用 wait(),wait(long)方法,join() 、 join(long, int) 、join(long, int)、sleep(long, int)或sleep(long, int)等方法後,處於WAITING、Timed Waiting狀態時,在該線程被調用interrupt方法後,線程的WAITING、Timed Waiting狀態將被清除,並拋出InterruptedException異常。
示例代碼:
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(){
@Override
public void run() {
while (true){
try {
System.out.println("running...");
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
/*
當線程處於 Waiting、TimedWaiting狀態,
執行interrupted方法後,會從Waiting、TimedWaiting中退出
並且isInterrupted=true的信號被擦除
*/
System.out.println(Thread.currentThread().getState());
System.out.println("isInterrupted:" + Thread.currentThread().isInterrupted());
}
}
}
};
testThread.start();
Thread.sleep(1000);
testThread.interrupt();
}
打印結果:
3.如果目標線程是被I/O 或者NIO中的Channel所阻塞,同樣,I/O操作會被中斷或者返回特
殊異常值。
4.park()\parkNanos方法執行後,線程也處於 WAITING、Timed Waiting,也會被喚醒,但是不會拋異常,且有很詭異的情況發生。
示例代碼:
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new Runnable() {
@Override
public void run() {
while(true){
LockSupport.park();
System.out.println("ing...");
}
}
});
testThread.start();
Thread.sleep(1000L);
testThread.interrupt();
System.out.println("============end=============================");
}
打印結果
deamon線程
定義:
守護線程
是指在程序運行的時候在後臺提供一種通用服務的線程,
進程結束時,會殺死所有守護線程。
注意點:
1.在Daemon線程中產生的新線程也是Daemon的
2.不能把正在運行的常規線程設置爲守護線程,thread.setDaemon(true)必須在thread.start()之前設置,否則會跑出一個IllegalThreadStateException異常。
3.守護線程它會在任何時候甚至在一個操作的中間發生中斷,因此應該永遠不去訪問固有資源,如文件、數據庫等等
CountDownLatch倒計時器
作用:
countDownLatch可以使一個線程等待其他線程各自執行完畢後再執行。
示例代碼:
public class Demo_CountDownLatch {
static AtomicLong num = new AtomicLong(0);
public static void main(String args[]) throws InterruptedException {
CountDownLatch ctl = new CountDownLatch(10);
for (int i=0; i< 10; i++){
new Thread(){
@Override
public void run() {
for (int j=0; j< 1000; j++){
num.getAndIncrement();
}
ctl.countDown();
}
}.start();
}
//設置開關,設置門栓
ctl.await();
System.out.println(num.get());
}
}
Semaphore計數信號量
作用:
常用於限制可以訪問某些資源(物理或邏輯的)線程數目。
是一種用來控制併發量的共享鎖。
示例代碼:
public class Demo_Semaphore {
public static void main(String args[]){
Semaphore sp = new Semaphore(10);
//短時間發送1000個請求,併發會很高,數據庫會受不了
for (int i=0; i<1000; i++){
new Thread(){
@Override
public void run() {
try {
sp.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
//模擬DB查詢
queryDb("localhost:3306");
sp.release();
}
}.start();
}
}
//發送一個HTTP請求
public static void queryDb(String uri) {
System.out.println("query===>: " + uri);
// 類似sleep的作用
LockSupport.parkNanos(1000 * 1000 * 1000);
}
}
CyclicBarrier循環柵欄
作用:
可以循環利用的屏障
示例代碼:
public class Demo_CyclicBarrier {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(5,// 柵欄一次通過的請求數
new Runnable() {
@Override
public void run() {
System.out.println(">>> 這是一個柵欄。。。");
}
});
//傳入一個Runnable,打印柵欄
for (int i=0; i< 100; i++){
new Thread(){
@Override
public void run() {
try {
barrier.await(); //
System.out.println("請求...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}.start();
LockSupport.parkNanos(1000 * 1000 * 1000L);
}
}
}