一短条、目的
- 學(xué)習(xí)進(jìn)程和線程的概念
- 學(xué)會(huì)實(shí)現(xiàn)Runnable接口創(chuàng)建線程
- 了解synchronized線程同步
- 學(xué)會(huì)使用Lock加鎖
- 使用接口實(shí)現(xiàn)主線程和子線程的數(shù)據(jù)回調(diào)
二、相關(guān)技術(shù)
1.多線程
進(jìn)程:正在運(yùn)行的一個(gè)程序QQ IDE 瀏覽器
系統(tǒng)會(huì)為這個(gè)進(jìn)程分配獨(dú)立的內(nèi)存資源
線程:具體執(zhí)行任務(wù)的最小單位
一個(gè)進(jìn)程最少擁有一個(gè)線程(主線程 運(yùn)行起來就執(zhí)行的線程)
線程之間是共享內(nèi)存資源的(經(jīng)常申請(qǐng)的)
線程之間可以通信(數(shù)據(jù)傳遞:多數(shù)為主線程和子線程)
每一個(gè)線程都有自己的運(yùn)行回路(生命周期)
線程的生命周期 狀態(tài)
NEW:新建 線程剛被創(chuàng)建好
RUNNABLE:就緒狀態(tài) 只要搶到時(shí)間片就可以運(yùn)行這個(gè)線程
BLOCKED:阻塞狀態(tài) sleep wait
WAITING:等待 wait
TIMED_WAITING,
TERMINATED:終止
- 1.如何創(chuàng)建一個(gè)線程 Thread Runable
- 2.線程的同步 synchronized ReentrantLock
- 3.主線程和子線程之間使用接口回調(diào)數(shù)據(jù)
- 4.線程間的通信:synchronized(wait notifi notifiall)
ReentrantLock lock;
Condition c=lock.newCondition();
await single songleall
2. 為什么需要?jiǎng)?chuàng)建子線程
- 在主線程中存在比較耗時(shí)的操作:下載視頻 上傳文件 數(shù)據(jù)
這些操作會(huì)阻塞主線程踱蛀,后面的任務(wù)必須等這些任務(wù)執(zhí)行完畢之后才能執(zhí)行 用戶體驗(yàn)比較差 - 為了不阻塞主線程姐扮,需要將耗時(shí)的任務(wù)放在子線程中去處理
3.如何創(chuàng)建一個(gè)子線程
- 1.定義一個(gè)類繼承于Thread 實(shí)現(xiàn)run方法
join:讓當(dāng)前這個(gè)線程阻塞 等join的線程執(zhí)行完畢再執(zhí)行
setName:設(shè)置線程名稱
getName:獲取線程名稱
currentThread:獲取當(dāng)前運(yùn)行的線程對(duì)象
start:開啟任務(wù)
- 2.實(shí)現(xiàn)Runnable接口 實(shí)現(xiàn)run方法
a.創(chuàng)建任務(wù) 創(chuàng)建類實(shí)現(xiàn)Runnable
b.使用Thread 為這個(gè)任務(wù)分配線程
c.開啟任務(wù) start
4.線程安全
- synchronized Lock 加鎖解鎖
- synchronized 同步監(jiān)聽器 需要一把鎖
- 任何一個(gè)對(duì)象都有自己的一把鎖
- 如果多個(gè)線程操作同一個(gè)代碼塊抽活,并且需要同步
- 那么必須操作同一個(gè)對(duì)象/同一個(gè)對(duì)象的同一把鎖
- 1.同步代碼塊
synchronized(監(jiān)聽器/對(duì)象/鎖){
需要同步的代碼
} - 2.同步方法
public synchronized void test(){}
本質(zhì)是同步代碼塊 等價(jià)于
synchronized(this){
test();
}
三、技術(shù)的使用
1.使用繼承Thread創(chuàng)建線程
class TestThread extends Thread {
//實(shí)現(xiàn)Run方法
//方法里面就是具體需要執(zhí)行的代碼
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name);
for (int i = 0; i < 100; i++) {
System.out.println(name + ":" + (i + 1));
}
super.run();
}
}
2.創(chuàng)建線程
TestThread tt=new TestThread();
//設(shè)置線程的名稱
tt.setName("子線程1");
//開啟任務(wù)
tt.start();
TestThread tt2=new TestThread();
//設(shè)置線程的名稱
tt2.setName("子線程2");
//開啟任務(wù)
tt2.start();
3.實(shí)現(xiàn)Runnable接口創(chuàng)建線程
class YThread implements Runnable{
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
4.Runnable接口使用方式
(1)
//創(chuàng)建一個(gè)任務(wù):創(chuàng)建一個(gè)類實(shí)現(xiàn)Runnable接口
YThread yt=new YThread();
//使用Thread操作這個(gè)任務(wù)
Thread t=new Thread(yt);
t.setName("子線程1");
t.start();
Thread t2=new Thread(yt);
t2.setName("子線程2");
t2.start();
(2)
Thread t=new Thread(new Runnable()){
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
t.setName("子線程1");
t.start();
(3)
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}).start();
(4)
//使用Lambda表達(dá)式
//不建議:閱讀性太差
new Thread(()->{
for (int i = 1; i <=100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}).start();
5.使用RuntrantLock同步
//創(chuàng)建一個(gè)可重入的鎖
static ReentrantLock lock=new ReentrantLock();
for (int i = 1; i <=100 ; i++) {
//加鎖
lock.lock();
if (num>0){
System.out.println(name+"出票"+num);
num--;
try {
condition.signal();
condition.await();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
}
}else {
break;
}
//解鎖
lock.unlock();
}
}