什麼shi線程
線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際單位
一個進程有多個線程,通過cup的切換來
爲什麼要用多線程
如果我們同時操作兩個文檔,這時候我麼用多線程 這樣有提高我們性能,
異步執行
利用多CPU 資源實現真正意義上的並行執行
線程應用場景
多線程實現文件下載
後臺任務,如向大量用戶發送郵件
異步處理信息,記錄日誌
多步驟的任務處理,多任務分割,由一個主線程分割給多個線程完成,
總的來說
合理利用cpu資源來實現線程的並行處理,來實現一個線程內的多個任務的並行執行,同時基於線程本身的異步特性實現任務處理的效率
- 繼承 Thread 類
public class ThreadDome extends Thread {
@Override
public void run() {
System.out.println("dangqi--:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
ThreadDome threadDome = new ThreadDome();
threadDome.start();
}
}
- 實現Runable 接口
public class Runnable implements java.lang.Runnable {
public void run() {
System.out.println("dangqi"+Thread.currentThread().getName());
}
public static void main(String[] args) {
Runnable runnable = new Runnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
- 實現 Callable接口
public class Callable implements java.util.concurrent.Callable {
public Object call() throws Exception {
System.out.println("當前"+Thread.currentThread().getName());
return "Callable";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future submit = executorService.submit(new Callable());
System.out.println(submit.get());
}
}
線程生命週期
- new 初始狀態 線程構建,但還沒有調用Start方法,
- runnabled 運行狀態,jvm線程把操作系統中的就緒狀態和運行狀態統一稱爲行中”
- blocked 阻塞狀態 表示線程進入等待狀態 因某種原因放棄cpu
- waiting 等待狀態
- time_wating 超時等待狀態,超時自動返回
- terminated 終止狀態,表示當前線程執行完畢
Thread.sleep(0)的意義 就
是在o的時候讓出cpu後0之後搶佔cpu,可以說是重新分配cup的一個過程
Thread.sleep(0)工作流程
- 掛起線程修改運行狀態
- 用sleep()提供的參數來設置一個定時器
- 當時間結束,定時器觸發,內核收到中斷後修改線程的運行狀態
wait() 和notifyAll();,notify()
- wait()使當前線程進入等待隊列,並釋放該線程所擁有的鎖,(而sleep()方法掛起當前線程,並不釋放該線程所擁有的鎖)等待某個條件發生變化,再由其他線程喚醒(notify)。
- wait()方法可以有一個參數,就是等待的最長時間,若等待時長超過最長時間,該線程會從wait()中恢復執行。
- notify()用來喚醒由wait()引起的被掛起的線程,當一個線程調用notify()時,在衆多等待同一個鎖的任務中的其中一個會被喚醒。
- notifyAll()將喚醒所有等待當前線程所擁有的鎖的線程,
wait() 和notify實現多個線程之間的通信如生產者和消費者
生產者
public class Producer implements Runnable {
private Queue<String> bags;
private int size;
public Producer(Queue<String> bags, int size) {
this.bags = bags;
this.size = size;
}
@Override
public void run() {
try {
int i = 0;
while (true) {
i++;
synchronized (bags) {
while (bags.size() == size) {
System.out.println("bags滿了");
//TODO 阻塞
bags.wait();
}
Thread.sleep(1000);
System.out.println("生產者生一個" + i);
bags.add("bag" + i);
//喚醒阻塞下的消費者
bags.notifyAll();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
消費者
public class Consumer implements Runnable {
private Queue<String> bags;
private int size;
public Consumer(Queue<String> bags, int size) {
this.bags = bags;
this.size = size;
}
@Override
public void run() {
try {
while (true) {
synchronized (bags) {
while (bags.isEmpty()) {
System.out.println("bags爲空了");
bags.wait();
}
Thread.sleep(1000);
String remove = bags.remove();
System.out.println("消費者消費" + remove);
//喚醒阻塞下的生產着
bags.notifyAll();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
所謂的生產着和消費者
他們是雙向阻塞雙向喚醒的一個操作
他們共用一個隊列 共用一個size大小
就像生產商的產品,放到商店裏,這時候消費者吧這個產品消費了,這是一個正常的關係,但是如果商店的產品放滿了,商店告訴生產商先等一等在生產,但是如果商店的產品消費完了,商店告訴消費者等一等,這時候通過某種傳遞 ,消費者喚醒生產者,開始生產,,這時候有產品,生產商有傳遞給消費者有產品了可以消費了,就是喚醒消費者
線程中斷
- 線程處於阻塞下(join() wait())
- while()循環
線程結束: 是ran方法運行結束
public class stopDemo {
private static int i;
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (!Thread.currentThread().isInterrupted())
i++;
});
thread.start();
thread.interrupt(); //中斷線程
}
thread.interrupt();結束線程
Thread.currentThread().isInterrupted()
interrupted 返回一箇中斷標誌
看實例
public class StopInterr {
private static int i;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() ->{
while (true){
if (Thread.currentThread().isInterrupted()){
System.out.println("be"+Thread.currentThread().isInterrupted());
Thread.interrupted();
System.out.println("uf"+Thread.currentThread().isInterrupted());
}
}
});
thread.start();
thread.sleep(1000);
thread.interrupt();
}
}
打印======
betrue
uffalse
相當於開關復位一樣。