目的:多線程是知識體系中一重要的部分虱歪,使用多線程能同步完成多個(gè)任務(wù)蜂绎,提高資源使用效率進(jìn)而提高系統(tǒng)的效率。
線程所需掌握知識點(diǎn):
- 1.如何創(chuàng)建一個(gè)線程 Thead Runnable
- 2.線程的同步
- 3.主線程與子線程之間使用接口回調(diào)數(shù)據(jù)
- 4.線程之間的通信 :
synchronized (wait notify notifyALL)
ReentrantLock lock;
Condition c = lock.newCondition()
await single singleALL
技術(shù):
1.基本知識點(diǎn):
(1)進(jìn)程和線程
進(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ìn)程申請的)
線程之間可以通信(數(shù)據(jù)傳遞:多數(shù)情況下為主線程和子線程)
每一個(gè)線程都有自己的回路(生命周期)
(2)線程的生命周期 狀態(tài)
6441157D1DFF7B3DA414078385811477.jpg
NEW:新建 線程剛被創(chuàng)建好
RUNNABLE: runnable 就緒狀態(tài) 只要搶到時(shí)間片就可以運(yùn)行這個(gè)線程
BLOCKED :阻塞狀態(tài) sleep
WAITING :等待 wait
TIMED_WAITING
TERMINATED :終止
(3)為什么需要?jiǎng)?chuàng)建子線程
如果在主線程中存在比較耗時(shí)的操作:下載視頻 上傳文件 數(shù)據(jù)處理
這些操作會(huì)阻塞主線程 后面的任務(wù)必須等這些任務(wù)執(zhí)行完畢
之后才能執(zhí)行笋鄙,用戶體驗(yàn)感差
為了不阻塞主線程师枣,需要將耗時(shí)的任務(wù)放在子線程里面去執(zhí)行
2.如何創(chuàng)建子線程:
(1)寫一個(gè)類繼承于Thread 實(shí)現(xiàn)run方法
- join: 讓當(dāng)前這個(gè)線程阻塞,讓join的線程執(zhí)行完畢再執(zhí)行
- setName:設(shè)置線程名稱
- getName:獲取線程名稱
- currentThread:獲取當(dāng)前線程的線程對象
- start:開啟任務(wù)
eg:
class TextTHread extends Thread{
//實(shí)現(xiàn)run方法
//方法里面就是具體需要執(zhí)行的代碼
@Override
public void run(){
String name = Thread.currentThread().getName();
for (int i = 0; i < 100; i++) {
System.out.println(name+":"+(i+1));
}
super.run();
}
}
創(chuàng)建線程:
//main方法里面執(zhí)行的代碼 是在主線程里面執(zhí)行的
//主線程的名稱是main (不是main方法)
//System.out.println(Thread.currentThread().getName());
//創(chuàng)建Thread對象
TextTHread textTHread1 = new TextTHread();
//設(shè)置線程名稱
textTHread1.setName("子線程1");
//開啟任務(wù)
textTHread1.start();
textTHread2 = new TextTHread();
//設(shè)置線程名稱
textTHread2.setName("子線程2");
//開啟任務(wù)
textTHread2.start();
(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
eg:
class PXDThread implements Runnable{
@Override
public void run() {
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
調(diào)用方法1:
//2.1
PXDThread pt = new PXDThread();
//使用Thread操作這個(gè)任務(wù)
Thread t = new Thread(pt);
t.setName("子線程1:");
t.start();
Thread t2 = new Thread(pt);//一個(gè)任務(wù)可以由多個(gè)線程完成啊
t2.setName("子線程2:");
t2.start();
調(diào)用方法2:
//2.2
//這個(gè)任務(wù)只需要使用一次
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
});
t1.setName("子線程1:");
t1.start();
調(diào)用方法3:
//2.3
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}).start();
調(diào)用方法4:
//2.4
//使用Lambda表達(dá)式
//不建議 閱讀性太差
new Thread( () -> {
for (int i = 1; i <=100; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}).start();
3.線程安全:同步
線程安全 synchronized Lock 加鎖解鎖
synchronized 需要同步監(jiān)聽器 需要一把鎖
任何對象都有一個(gè)把鎖
如果多個(gè)線程操作同一一個(gè)代碼塊萧落,并且需要同步
那么就需要操作同一個(gè)對象/同一個(gè)對象的同一把鎖
synchronized(監(jiān)聽器/對象/鎖)
eg:火車票賣票 全國的賣票系統(tǒng)就一個(gè)
(1)synchronized:
synchronized(監(jiān)聽器/對象/鎖)
1.同步代碼塊
synchronized(監(jiān)聽器/對象/鎖){
需要同步的代碼
}
//用于賣票的任務(wù)
class Ticket implements Runnable{
//定義所有車票的數(shù)量
public static int num = 100;
String name;
public Ticket(String name){
this.name = name;
}
static final Object obj =new Object();
//創(chuàng)建一個(gè)可重新載入的鎖
static ReentrantLock lock = new ReentrantLock();
public void run() {
for(int i =1;i<=100;i++){
//判斷有沒有票
synchronized (obj){
//需要同步的代碼
if (num>0){
System.out.println(name+"出票:"+(101-num));
num--;
try {
//當(dāng)前線程等待
obj.notify();
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
}
}
}
(2)Lock:
2.同步方法 同步監(jiān)聽器就是當(dāng)前對象本身
必須保證多個(gè)對象調(diào)用的同步方法時(shí)操作的統(tǒng)一對象
public synchronized void text(){
本質(zhì)就是同步代碼塊
等價(jià)于
synchronized(this) {
text()践美;
}
以下代碼中未實(shí)現(xiàn)await single singleALL等線程狀態(tài)轉(zhuǎn)換方法
//用于賣票的任務(wù)
class Ticket implements Runnable{
//定義所有車票的數(shù)量
public static int num = 100;
String name;
public Ticket(String name){
this.name = name;
}
static final Object obj =new Object();
//創(chuàng)建一個(gè)可重新載入的鎖
static ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void run() {
for(int i =1;i<=100;i++){
//判斷有沒有票
// synchronized (obj){
// //需要同步的代碼
//加鎖
lock.lock();
if (num>0){
System.out.println(name+"出票:"+(101-num));
num--;
lock.newCondition();
}else{
break;
}
//解鎖
lock.unlock();
}
}
}
調(diào)用:
// 火車票賣票
// 全國的賣票系統(tǒng)就一個(gè)
Ticket ticketCQ = new Ticket("重慶");
Thread t1 = new Thread(ticketCQ);
t1.start();
Ticket ticketSH = new Ticket("上海");
Thread t2 = new Thread(ticketSH);
t2.start();
運(yùn)行結(jié)果太長洗贰,不予展現(xiàn)。
4.使用接口實(shí)現(xiàn)線程之間數(shù)據(jù)回調(diào)
(1)定義線程里面 Agent類
public class Agent extends Thread{
AgentInterface target;
@Override
public void run() {
System.out.println("開始找房子");
System.out.println("---------");
System.out.println("房子找到了 即將返回?cái)?shù)據(jù)");
target.callBack("房子在XXX");
super.run();
}
public interface AgentInterface{
void callBack(String desc);
}
}
(2)定義Person類:
public class Person implements Agent.AgentInterface {
public void needHouse(){
Agent xw = new Agent();
xw.target = this; //表明返回?cái)?shù)據(jù)給調(diào)用者
xw.start();
}
@Override
public void callBack(String desc) {
System.out.println("我是小王拨脉,接受到你的數(shù)據(jù)"+desc);
}
}
(3)調(diào)用:
Person person = new Person();
person.needHouse();
運(yùn)行結(jié)果:
開始找房子
---------
房子找到了 即將返回?cái)?shù)據(jù)
我是小王哆姻,接受到你的數(shù)據(jù)房子在XXX
Process finished with exit code 0
心得:
java的學(xué)習(xí)要接近尾聲了,我越來越認(rèn)識到自己前面的知識點(diǎn)有些力不從心玫膀,比如代理設(shè)計(jì)模式矛缨,哎,得好好去復(fù)習(xí)了帖旨。