1: 概念
進(jìn)程:
進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序.每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi).
例如, 平時(shí)打開的酷狗音樂聽歌, 就是一個(gè)進(jìn)程.
(多)線程:
線程有時(shí)被稱為輕量進(jìn)程(Lightweight Process,LWP),是程序執(zhí)行流的最小單元.
線程是程序中一個(gè)單一的順序控制流程.進(jìn)程內(nèi)有一個(gè)相對(duì)獨(dú)立的门扇、可調(diào)度的執(zhí)行單元,是系統(tǒng)獨(dú)立調(diào)度和分派CPU的基本單位指令運(yùn)行時(shí)的程序的調(diào)度單位.在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線程完成不同的工作,稱為多線程.
進(jìn)程&線程關(guān)系:
進(jìn)程想要執(zhí)行任務(wù),必須有線程(每一個(gè)進(jìn)程至少要有一條線程);
線程是進(jìn)程的執(zhí)行單元,一個(gè)進(jìn)程(程序)的所有任務(wù)都在線程中執(zhí)行.
通常, 線程中的任務(wù)的執(zhí)行都是串行的, 在一個(gè)時(shí)間內(nèi), 一個(gè)線程只能執(zhí)行一個(gè)任務(wù).
為什么要多線程:
可以在一個(gè)進(jìn)程中開啟多條線程, 每條線程可以并行(同行)執(zhí)行不同的任務(wù),充分利用CPU,適當(dāng)?shù)奶岣叱绦虻膱?zhí)行效率.
2: 多線程中常用方法
方法 | 說明 |
---|---|
currentThread | 返回當(dāng)前正在執(zhí)行的線程對(duì)象的應(yīng)用 |
start | 使該線程開始執(zhí)行;Java 虛擬機(jī)調(diào)用該線程的 run 方法. 注意, 不要調(diào)用run方法啟動(dòng)線程, 啟動(dòng)線程是start, 如果調(diào)用run方法, 相當(dāng)于在主線程中調(diào)用run方法, 和普通的方法的調(diào)用沒有區(qū)別, 此時(shí)不會(huì)創(chuàng)建一個(gè)新的線程來執(zhí)行定義的任務(wù) |
run | 如果該線程是使用獨(dú)立的Runnable運(yùn)行對(duì)象構(gòu)造的,則調(diào)用該Runnable對(duì)象的run方法;否則,該方法不執(zhí)行任何操作并返回. |
setName | 改變線程名稱,使之與參數(shù)name相同. |
setPriority | 改變線程的優(yōu)先級(jí) |
setDeamon | 設(shè)置線程為守護(hù)線程或用戶線程 |
interrupt | 中斷線程 |
isAlive | 測試線程是否處于活動(dòng)狀態(tài). |
yield | 暫停當(dāng)前正在執(zhí)行的線程對(duì)象, 并執(zhí)行其他線程 |
sleep | 讓當(dāng)前正在執(zhí)行的線程休眠指定的毫秒數(shù) |
3: 如何創(chuàng)建線程
1: 普通創(chuàng)建 Thread() 對(duì)象
2: 繼承 Thread 類
3: 實(shí)現(xiàn) Runnable 接口
4: 實(shí)現(xiàn) Callable 接口, 實(shí)現(xiàn)Callable接口后, 可以有返回值
4: 實(shí)例講解多線程
例子1(new Thread):
//================Demo1
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread("thread1");
thread1.sleep(5000);
System.out.println("線程名稱: " + thread1.currentThread().getName());
Thread thread2 = new Thread("thread2");
thread2.sleep(5000);
System.out.println("線程名稱: " + thread2.currentThread().getName());
}
}
//================Demo2
public class Demo2 {
public static void main(String[] args) {
Thread thread1 = new Thread("Thread1"){
public void run() {
try {
Thread.sleep(5000);
System.out.println("線程名稱: " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
};
thread1.start();
Thread thread2 = new Thread("Thread2"){
public void run() {
try {
Thread.sleep(5000);
System.out.println("線程名稱: " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
};
thread2.start();
}
}
認(rèn)真體會(huì)一下上面2個(gè)demo, 想一想, 他們執(zhí)行完所花的時(shí)間一樣都是10毫秒嗎?
答案是否定的, Demo1執(zhí)行時(shí)間10毫秒, Demo2執(zhí)行時(shí)間為5毫秒. why?
因?yàn)榈谝粋€(gè)是在同一個(gè)主線程中. 打印的結(jié)果可以看到
Demo1:
線程名稱: main
線程名稱: main
Demo2:
線程名稱: Thread2
線程名稱: Thread1
例子2(extend Thread):
public class Main {
public static void main(String[] args) {
for (int i=0; i< 5; i++){
Thread thread = new MyThread();
thread.start();
}
}
}
public class MyThread extends Thread{
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日HH時(shí)mm分ss秒S毫秒");
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(df.format( new Date()) + " Thread:" + name + " start.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(df.format( new Date()) + " Thread:" + name + " end.");
}
}
===============以下是執(zhí)行結(jié)果
2018年09月25日18時(shí)35分10秒913毫秒 Thread:Thread-0 start.
2018年09月25日18時(shí)35分10秒914毫秒 Thread:Thread-1 start.
2018年09月25日18時(shí)35分10秒915毫秒 Thread:Thread-2 start.
2018年09月25日18時(shí)35分10秒916毫秒 Thread:Thread-3 start.
2018年09月25日18時(shí)35分10秒916毫秒 Thread:Thread-4 start.
2018年09月25日18時(shí)35分15秒914毫秒 Thread:Thread-1 end.
2018年09月25日18時(shí)35分15秒914毫秒 Thread:Thread-0 end.
2018年09月25日18時(shí)35分15秒916毫秒 Thread:Thread-2 end.
2018年09月25日18時(shí)35分15秒916毫秒 Thread:Thread-4 end.
2018年09月25日18時(shí)35分15秒916毫秒 Thread:Thread-3 end.
例子3(實(shí)現(xiàn)Runnable接口):
public class Main {
public static void main(String[] args) {
for(int i=0; i<5; i++){
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
}
public class MyRunnable implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日HH時(shí)mm分ss秒S毫秒");
System.out.println(df.format(new Date()) + " Thread:" + name + " start.");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(df.format(new Date()) + " Thread:" + name + " end.");
}
}
//===================結(jié)果, 也是只花了10秒
2018年09月25日18時(shí)41分43秒255毫秒 Thread:Thread-4 start.
2018年09月25日18時(shí)41分43秒255毫秒 Thread:Thread-2 start.
2018年09月25日18時(shí)41分43秒255毫秒 Thread:Thread-0 start.
2018年09月25日18時(shí)41分43秒255毫秒 Thread:Thread-1 start.
2018年09月25日18時(shí)41分43秒260毫秒 Thread:Thread-3 start.
2018年09月25日18時(shí)41分53秒257毫秒 Thread:Thread-4 end.
2018年09月25日18時(shí)41分53秒258毫秒 Thread:Thread-2 end.
2018年09月25日18時(shí)41分53秒258毫秒 Thread:Thread-0 end.
2018年09月25日18時(shí)41分53秒258毫秒 Thread:Thread-1 end.
2018年09月25日18時(shí)41分53秒262毫秒 Thread:Thread-3 end.
例子4(實(shí)現(xiàn)Callable接口):
實(shí)現(xiàn)callable之后, 如果有返回值的話, 就需要放到線程池中, 待全部執(zhí)行完了, 一起返回.
public class Main {
public static void main(String[] args) {
int poolsize = 3;
Date start = new Date();
List<Future> list = new ArrayList<Future>();
ExecutorService pool = Executors.newFixedThreadPool(poolsize);
for(int i =0; i<poolsize; i++){
Callable thread = new MyCallable();
Future result = pool.submit(thread);
list.add(result);
}
pool.shutdown();
list.forEach(item -> {
try {
System.out.println("線程返回值為: " + item.get().toString());
} catch (Exception e) {
e.printStackTrace();
}
});
Date end = new Date();
long sec = end.getTime() - start.getTime();
System.out.println("總共花費(fèi): " + sec + " 毫秒!");
}
}
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日HH時(shí)mm分ss秒S毫秒");
String name = Thread.currentThread().getName();
System.out.println(df.format(new Date()) + " Thread:" + name + " start.");
Thread.sleep(10000);
System.out.println(df.format(new Date()) + " Thread:" + name + " end.");
return name;
}
}
//===================結(jié)果, 也是只花了10秒
2018年09月25日18時(shí)45分54秒713毫秒 Thread:pool-1-thread-2 start.
2018年09月25日18時(shí)45分54秒716毫秒 Thread:pool-1-thread-3 start.
2018年09月25日18時(shí)45分54秒716毫秒 Thread:pool-1-thread-1 start.
2018年09月25日18時(shí)46分04秒714毫秒 Thread:pool-1-thread-2 end.
2018年09月25日18時(shí)46分04秒717毫秒 Thread:pool-1-thread-3 end.
2018年09月25日18時(shí)46分04秒717毫秒 Thread:pool-1-thread-1 end.
線程返回值為: pool-1-thread-1
線程返回值為: pool-1-thread-2
線程返回值為: pool-1-thread-3
總共花費(fèi): 10051 毫秒!