JavaSE-多執行緒
阿新 • • 發佈:2021-07-20
JavaSE-多執行緒
程式、程序、執行緒
- 程式(program)指的是指令和資料的有序集合,其本身沒有執行的含義,是一個靜態的概念。
- 程序(process)指的是一個程式執行一次的過程,他是一個動態的概念,是系統分配資源的單位
- 執行緒(thread),通常在一個程序中可以有多個執行緒,但是在程序中至少存在一個執行緒(主執行緒),是CPU排程和執行的單位
真正的多執行緒指的是有多個CPU,即多核。
在程式執行時,即便沒有自己建立執行緒也會有很多執行緒,如主執行緒、gc執行緒、
在一個程序中,如果開闢了多個執行緒,執行緒的執行由排程器(CPU)安排排程,排程器是與作業系統密切相關的,先後順序不能人為干預
對一份資源進行操作時,會存在資源搶奪問題,需要加入併發控制,對執行緒排隊
每個執行緒在自己的工作記憶體互動,記憶體控制不當會導致資料不一致
執行緒實現
- 繼承
Thread
類 - 實現
Runable
介面
ps:因為Java是單繼承,建議使用Runable
介面實現多執行緒。方便同一個物件被多個執行緒使用
TestThread testThread = new TestThread(); new Thread(testThread,"執行緒1").start() new Thread(testThread,"執行緒2").start() new Thread(testThread,"執行緒3").start()
extends Thread
- 自定義執行緒繼承
Thread
類 - 重寫
run()
方法,編寫執行緒執行體 - 建立執行緒物件,呼叫
start()
方法啟動現場,但執行緒不一定立即執行,聽CPU安排排程
//建立執行緒1:繼承Thread類,重寫run()方法,呼叫start()方法執行執行緒 public class CreateThreadDemo01 extends Thread{ //重寫run()方法 @Override public void run() { //run執行緒,run()方法體 System.out.println("Run()執行緒========" + i); } public static void main(String[] args) { //main執行緒,主執行緒 //建立一個執行緒物件 CreateThreadDemo01 createThreadDemo01 = new CreateThreadDemo01(); //呼叫start()方法執行執行緒 createThreadDemo01.start(); for (int i = 0; i < 2000; i++) { System.out.println("Main執行緒========" + i); } } }
其中,主執行緒和run()
方法執行緒交替執行,並不存在先後順序。
執行緒開啟不一定立即執行,由CPU排程執行。
載入第三方工具類庫
新建一個lib包,將下載好的jar包cv到lib包中,並右鍵 Add as Library
在專案資源目錄Project Structure
中Libraries
下就可以看到這個jar包了
繼承Thread類下載檔案
- 繼承
Thread
方法 - 建立一個類,在其中建立一個方法呼叫
org.apache.commons.io.
中的FileUtils.copyURLToFile()
方法下載網路上的檔案 - 重寫
run()
方法呼叫上面寫好的下載檔案的方法 - 建立有參構造方法使新建
thread
時可以直接穿入引數url
和filename
main()
方法中新建子執行緒並start()
子執行緒
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//練習Thread 實現多執行緒同步下載
public class TestThreadDemo02 extends Thread{
private String url; //網路檔案的url
private String filename; //要儲存的檔名
@Override
public void run() {
//子執行緒要進行的操作
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, filename);
System.out.println("檔案下載完成,位於: " + filename);
}
//有參構造方法
public TestThreadDemo02(String url, String filename){
this.url = url;
this.filename = filename;
}
public static void main(String[] args) {
//建立子執行緒
TestThreadDemo02 thread01 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
"/Users/b/Desktop/01.png");
TestThreadDemo02 thread02 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
"/Users/b/Desktop/02.png");
TestThreadDemo02 thread03 = new TestThreadDemo02("https://images.cnblogs.com/cnblogs_com/ache/1644357/o_20022410503214.jpg",
"/Users/b/Desktop/03.jpg");
//執行子執行緒
thread01.start();
thread02.start();
thread03.start();
}
}
class WebDownloader {
public void downloader(String url, String filename){
try {
FileUtils.copyURLToFile(new URL(url), new File(filename));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO錯誤,WebDownloader方法存在問題");
}
}
}
implements Runable
implements Runnable
介面- 重寫
run()
方法 - 需要一個實現
Runable
介面的類的物件作為引數傳入Thread
類中呼叫start()
方法
//實現runable介面,重寫run方法,需要一個runable介面的實現類作為引數傳入thread類中呼叫start方法 實現多執行緒
//實現runable介面
public class RunableThreadDemo01 implements Runnable{
public static void main(String[] args) {
//new一個runable介面的實現類
RunableThreadDemo01 runableThreadDemo01 = new RunableThreadDemo01();
//傳入實現類並呼叫start
new Thread(runableThreadDemo01).start();
for (int i = 0; i <2000; i++) {
System.out.println("main執行緒========" + i);
}
}
//重寫run方法
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("run執行緒===========" + i);
}
}
}
實現Runable介面多執行緒下載檔案
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//實現多執行緒
public class TestThreadDemo01 implements Runnable{
private String url;
private String filename;
@Override
public void run() {
//子執行緒要進行的操作
WebDownloader02 webDownloader02 = new WebDownloader02();
webDownloader02.downloader(url, filename);
System.out.println("檔案下載完成,位於: " + filename);
}
public TestThreadDemo01(String url, String filename){
this.url = url; //網路檔案的url
this.filename = filename; //檔名
}
public static void main(String[] args) {
TestThreadDemo02 thread01 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
"/Users/b/Desktop/01.png");
TestThreadDemo02 thread02 = new TestThreadDemo02("https://pic.cnblogs.com/avatar/1835657/20210311181843.png",
"/Users/b/Desktop/02.png");
TestThreadDemo02 thread03 = new TestThreadDemo02("https://images.cnblogs.com/cnblogs_com/ache/1644357/o_20022410503214.jpg",
"/Users/b/Desktop/03.jpg");
new Thread(thread01).start(); //執行該子執行緒
new Thread(thread02).start();
new Thread(thread03).start();
}
}
class WebDownloader02 {
public void downloader(String url, String filename){
try {
FileUtils.copyURLToFile(new URL(url), new File(filename));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO錯誤,WebDownloader方法存在問題");
}
}
}
多個執行緒操作一個物件
public class TestThreadDemo03 implements Runnable{
private int ticketNums = 10;
@Override
public void run() {
while (true){
if (ticketNums >= 0){
try {
//模擬延時
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums + "票");
ticketNums--;
}else{
break;
}
}
}
public static void main(String[] args) {
TestThreadDemo03 testThreadDemo03 = new TestThreadDemo03();
new Thread(testThreadDemo03, "Ago").start();
new Thread(testThreadDemo03, "Kfei").start();
new Thread(testThreadDemo03, "Xming").start();
new Thread(testThreadDemo03, "Zgou").start();
}
}
執行結果,其中Kfei和Ago都拿到了第2票,第10票,多個執行緒操作同一個資源時出現數據混亂的問題
Kfei拿到了第10票
Ago拿到了第10票
Kfei拿到了第9票
Ago拿到了第8票
Kfei拿到了第7票
Ago拿到了第6票
Kfei拿到了第5票
Ago拿到了第4票
Ago拿到了第2票
Kfei拿到了第2票
Ago拿到了第1票
Kfei拿到了第0票
執行緒狀態
執行緒五大狀態
- 建立狀態:當
new
一個新的執行緒物件時,就進入了建立狀態 - 就緒狀態:當呼叫
start()
方法時,執行緒進入就緒狀態,但不是立即執行,需要等待CPU排程 - 阻塞狀態:當呼叫
sleep()
、wait()
或同步鎖定時,執行緒進入阻塞狀態,等阻塞事件結束後重新進入就緒狀態 - 執行狀態:獲得CPU資源真正開始執行執行緒
- 死亡狀態:執行緒中斷或結束
執行緒方法
方法 | 說明 |
---|---|
setPriority(int newPriority) |
更改執行緒優先順序 |
static void sleep(long millis) |
使當前執行緒休眠指定的毫秒數 |
void join() |
等待該執行緒中止 |
static void yeild() |
暫停當前執行的執行緒物件,並執行其他執行緒 |
void interupt() |
中斷執行緒(不建議) |
boolean isAlive() |
判斷執行緒是否存活 |
停止執行緒
推薦設定迴圈次數使用標誌位來控制執行緒的啟停
//建立標誌位,
private boolean flag = true;
@Override
public void run() {
//利用標誌位控制執行緒啟停
int i = 0;
while (flag){
System.out.println("執行緒" + Thread.currentThread().getName() + "開始 " + i++);
}
}
//對外提供方法用於停止執行緒
public void stop(){
this.flag = false;
System.out.println("執行緒" + Thread.currentThread().getName() + "結束");
}
public static void main(String[] args) {
TestStopDemo testStopDemo = new TestStopDemo();
new Thread(testStopDemo, "Thread1").start();
new Thread(testStopDemo, "Thread2").start();
testStopDemo.stop();
}
執行緒休眠 sleep()
@Override
public void run() {
while (true){
if (ticketNums >= 0){
try {
//模擬延時
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
模擬倒計時
public class TestTimeDownDemo implements Runnable{
@Override
public void run() {
Date starttime = new Date(System.currentTimeMillis());//獲取系統當前時間
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(starttime));
starttime = new Date(System.currentTimeMillis());//更新當前時間
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
TestTimeDownDemo testTimeDownDemo = new TestTimeDownDemo();
new Thread(testTimeDownDemo).start();
}
}
執行緒禮讓 yield()
禮讓不一定成功,看CPU
public class TestYieldDemo {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"thread1").start();
new Thread(myYield,"thread2").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "執行緒開始執行");
Thread.yield(); //執行緒禮讓
System.out.println(Thread.currentThread().getName() + "執行緒停止執行");
}
}
執行緒強制執行 join()
Join()
合併執行緒,待此執行緒執行結束後,再執行其他執行緒,這期間其他執行緒阻塞
public class TestJoinDemo implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20000; i++) {
System.out.println("join執行緒執行" + i);
}
}
public static void main(String[] args) {
//執行子執行緒
TestJoinDemo testJoinDemo = new TestJoinDemo();
Thread thread = new Thread(testJoinDemo);
thread.start();
//main執行緒
for (int i = 0; i < 200; i++) {
if (i==20){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main執行緒" + i);
}
}
}
所有內容僅限於維護網路安全學習參考