国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

多線程基礎(chǔ)(二)

2019-11-08 01:57:15
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

一 線程間通信

1.線程間通信: 實(shí)際就是多個(gè)線程在操作同一資源,但是操作的動(dòng)作不同 要求: 有一個(gè)資源Res,成員變量為name和sex; 有兩個(gè)進(jìn)程input和output用來(lái)操作資源res,其中input用于設(shè)置資源,output用于取出資源。

package transportation;class Res{ String name; String sex;}class Input implements Runnable{ PRivate Res r; //采用帶參數(shù)的默認(rèn)構(gòu)造函數(shù),用于保證輸入和輸出進(jìn)程控制的是同一資源 Input(Res r){ this.r=r; } //如果將此函數(shù)變?yōu)橥胶瘮?shù),那么成為單線程函數(shù); //需要分析清楚那些需要采用同步,哪些不需要 public void run(){ int x=0; while(true){ //同步的參數(shù)為r,可以設(shè)置為Input.class或者output.class synchronized(r){ if(x%2==0){ r.name="mike"; r.sex="man"; } else { r.name="Lily"; r.sex="woman"; } x++; } } }}class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ synchronized(r){ System.out.println(r.name+"..."+r.sex); } } }}public class Trans { public static void main(String[] args) { Res r=new Res();//一堆煤 即資源 Input i=new Input(r);//兩個(gè)大卡車,一進(jìn)一出 Output o=new Output(r); Thread t1=new Thread(i);//兩條公路 Thread t2=new Thread(o); t1.start(); t2.start(); }}

此時(shí),出現(xiàn)的結(jié)果為: 這里寫圖片描述 理想結(jié)果應(yīng)該為mike和Lily相互交錯(cuò) 分析原因: 程序中沒(méi)有設(shè)置兩個(gè)進(jìn)程必須一前一后輪流交替運(yùn)行 2.解決方案:為資源設(shè)置一個(gè)成員變量flag,用于控制輸入和輸出進(jìn)程的執(zhí)行順序 代碼如下:

class Res{ String name; String sex; boolean flag=false;}class Input implements Runnable{ private Res r; //同步鎖在資源上,用來(lái)保證兩個(gè)同步函數(shù)使用同一個(gè)鎖 Input(Res r){ this.r=r; } //如果將此函數(shù)變?yōu)橥胶瘮?shù),那么成為單線程 public void run(){ int x=0; while(true){ synchronized(r){ if(r.flag==true){ try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(x%2==0){ r.name="mike"; r.sex="man"; } else { r.name="Lily"; r.sex="woman"; } x++; r.flag=true; r.notify(); } } }}class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ synchronized(r){ if(r.flag==false){ try { r.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(r.name+"..."+r.sex); r.flag=false; r.notify(); } } }}public class Trans { public static void main(String[] args) { Res r=new Res();//一堆煤 Input i=new Input(r);//兩個(gè)大卡車,一進(jìn)一出 Output o=new Output(r); Thread t1=new Thread(i);//兩條公路 Thread t2=new Thread(o); t1.start(); t2.start(); }}

標(biāo)注: 1) notifyAll();喚醒所有進(jìn)程 notify( ) 喚醒一個(gè)進(jìn)程 wait( ) 使一個(gè)進(jìn)程進(jìn)入等待狀態(tài) 2)使用flag來(lái)控制線程的運(yùn)行, flag==false 進(jìn)程Input可以運(yùn)行 flag==true 進(jìn)行Output可以運(yùn)行 3) Wait和notify,notifyAll都使用同步中,因?yàn)橐獙?duì)持有監(jiān)視器(鎖)的線程操作 所以要使用在同步中,因?yàn)橹挥型讲胖挥墟i的概念

為什么這些操作線程的方法要定義在Object類中? 因?yàn)檫@些方法在操作同步中線程時(shí),都必須要標(biāo)識(shí)他們所操作的線程所獨(dú)有的鎖。只有同一個(gè)鎖上的被等待線程 可以被同一鎖的notify喚醒,不可以對(duì)不同鎖中的線程進(jìn)行喚醒。即等待和喚醒是同一把鎖 而鎖可以是任意對(duì)象,所以定義在Object類中 3.代碼優(yōu)化

class Res{ private String name; private String sex; private boolean flag=false; public synchronized void set(String name,String sex){ if(flag==true){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name=name; this.sex=sex; flag=true; this.notify(); } public synchronized void out(){ if(flag==false) { try { this.wait(); } catch (Exception e) { } } System.out.println(name+"..."+sex); flag=false; this.notify(); }}class Input implements Runnable{ private Res r; //同步鎖在資源上,用來(lái)保證兩個(gè)同步函數(shù)使用同一個(gè)鎖 Input(Res r){ this.r=r; } //如果將此函數(shù)變?yōu)橥胶瘮?shù),那么成為單線程 public void run(){ int x=0; while(true){ if(x%2==0){ r.set("mike","man"); } else { r.set("Lily","Woman"); } x++; } }}class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run(){ while(true){ r.out(); } }}public class Trans { public static void main(String[] args) { Res r=new Res();//一堆煤 new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); }}

二 生產(chǎn)者消費(fèi)者實(shí)例

1. 要求:輸入輸出打印編號(hào); 兩個(gè)進(jìn)程,一個(gè)負(fù)責(zé)輸入,一個(gè)負(fù)責(zé)輸出

package transportation;class Resource{ private String name; private int count=1; private boolean flag=false; public synchronized void set(String name){ if(flag==true){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生產(chǎn)者..."+this.name); flag=true; this.notify(); } public synchronized void out(){ if(!flag) { try { this.wait(); } catch (Exception e) { } } System.out.println(Thread.currentThread().getName()+"...消費(fèi)者..."+this.name); flag=false; this.notify(); }}class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res=res; } public void run() { while(true){ res.set("+product+"); } }}class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res=res; } public void run() { while(true){ res.out(); } }}public class PV { public static void main(String[] args) { Resource r=new Resource(); Producer pro=new Producer(r); Consumer con=new Consumer(r); Thread t1=new Thread(pro); Thread t2=new Thread(con); t1.start(); t2.start(); }}

結(jié)果符合預(yù)期要求 這里寫圖片描述 2. 將主函數(shù)改為如下的代碼段來(lái)設(shè)置多個(gè)線程同時(shí)運(yùn)行

Thread t1=new Thread(pro); Thread t2=new Thread(con); Thread t3=new Thread(pro); Thread t4=new Thread(con); t1.start(); t2.start(); t3.start(); t4.start();

結(jié)果如下,可知出現(xiàn)問(wèn)題 這里寫圖片描述 原因: 并不是每次進(jìn)程被喚醒都會(huì)判斷標(biāo)記; notify喚醒的是線程池中的第一個(gè); 會(huì)導(dǎo)致數(shù)據(jù)混亂 3.改進(jìn)的代碼: 1)notify->notifyAll //喚醒所有的線程而非線程池中的第一個(gè)線程 if(flag)->while(flag)//每次線程被喚醒之后都需要判斷標(biāo)志位 if(!flag)->while(!flag) 2) 有多個(gè)線程時(shí), 判斷標(biāo)記位需要while,喚醒線程需要notifyAll

package transportation;class Resource{ private String name; private int count=1; private boolean flag=false; public synchronized void set(String name){ while(flag==true){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生產(chǎn)者..."+this.name); flag=true; this.notifyAll(); } public synchronized void out(){ while(!flag) { try { this.wait(); } catch (Exception e) { } } System.out.println(Thread.currentThread().getName()+"...消費(fèi)者..."+this.name); flag=false; this.notifyAll(); }}class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res=res; } public void run() { while(true){ res.set("+product+"); } }}class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res=res; } public void run() { while(true){ res.out(); } }}public class PV { public static void main(String[] args) { Resource r=new Resource(); Producer pro=new Producer(r); Consumer con=new Consumer(r); Thread t1=new Thread(pro); Thread t2=new Thread(con); Thread t3=new Thread(pro); Thread t4=new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); }}

原因: 1.對(duì)于多個(gè)生產(chǎn)者和消費(fèi)者,為什么要定義while判斷標(biāo)記 原因:讓被喚醒的線程再一次判斷標(biāo)記 2.為什么定義notifyAll

三. JDK5升級(jí)后的新特性

java.util.concurrent.locks JDK1.5 提供了多線程升級(jí)解決方案。 將同步synchronized替換為lock操作,將object中的wait,notify,notifyAll,替換為condition對(duì)象。 API中的代碼

class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }

生產(chǎn)者消費(fèi)者升級(jí)代碼JDK1.5 1)顯式鎖機(jī)制 2)顯示鎖上的等待喚醒機(jī)制 該實(shí)例中實(shí)現(xiàn)了只喚醒對(duì)方的操作.

import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;class Resource{ private String name; private int count=1; private boolean flag=false; //創(chuàng)建鎖和condition private Lock lock=new ReentrantLock(); private Condition condition_pro=lock.newCondition();//生產(chǎn)者 private Condition condition_con=lock.newCondition();//消費(fèi)者 public void set(String name) throws InterruptedException { lock.lock();//拿到鎖 try{ while(flag==true){ condition_pro.await(); //生產(chǎn)者等待 } this.name=name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生產(chǎn)者..."+this.name); flag=true; condition_con.signalAll();//消費(fèi)者喚醒 }finally{ lock.unlock();//釋放鎖 } } public void out() throws InterruptedException { lock.lock(); try{ while(!flag) condition_con.await();//消費(fèi)者等待 System.out.println(Thread.currentThread().getName()+"...消費(fèi)者..."+this.name); }finally{ lock.unlock(); } condition_pro.signalAll();//喚醒生產(chǎn)者 flag=false; }}class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res=res; } public void run() { while(true){ try{ res.set("+product+"); }catch(InterruptedException ex){ } } }}class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res=res; } public void run() { while(true){ try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } }}public class PV { public static void main(String[] args) { Resource r=new Resource(); Producer pro=new Producer(r); Consumer con=new Consumer(r); Thread t1=new Thread(pro); Thread t2=new Thread(con); Thread t3=new Thread(pro); Thread t4=new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); }}

四.線程的操作

1.停止線程 stop方法已經(jīng)過(guò)時(shí)。 如何停止線程? 只有一種方法:run方法運(yùn)行結(jié)束 開啟多線程運(yùn)行,運(yùn)行代碼通常是循環(huán)結(jié)構(gòu)。只要控制住循環(huán),就可以讓run方法運(yùn)行結(jié)束,也就是線程結(jié)束。

1)正常代碼:程序可以自然終止

package transportation;class StopThread implements Runnable{ boolean flag=true; public void run() { while(flag){System.out.println(Thread.currentThread().getName()+"....run"); } } public void changeFlag(){ flag=false; }}public class StopThreadDemo { public static void main(String[] args) { StopThread t=new StopThread(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); int num=0; while(true){ if(num++==60){ t.changeFlag(); break; } System.out.println(Thread.currentThread().getName()+"...."+num); } }}

2)異常代碼:線程沒(méi)有正常結(jié)束

package transportation;/*不是死循環(huán),代碼并沒(méi)有消耗資源;當(dāng)線程處于凍結(jié)狀態(tài),就不會(huì)讀取到標(biāo)記,則線程不會(huì)運(yùn)行*/class StopThread implements Runnable{ boolean flag=true; /*當(dāng)線程1或線程2開啟后,線程進(jìn)入后,wait()被鎖住*/ public synchronized void run() { while(flag){ try { wait(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+"....Exception"); } System.out.println(Thread.currentThread().getName()+"....run"); } } public void changeFlag(){ flag=false; }}public class StopThreadDemo { public static void main(String[] args) { StopThread t=new StopThread(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); int num=0; while(true){ if(num++==60){ t.changeFlag(); break; } System.out.println(Thread.currentThread().getName()+"...."+num); } }}

結(jié)果為: 這里寫圖片描述 3)interrupt將處于凍結(jié)狀態(tài)的線程強(qiáng)制恢復(fù)為運(yùn)行狀態(tài)

package transportation;/*當(dāng)沒(méi)有指定的方式讓凍結(jié)的線程恢復(fù)運(yùn)行狀態(tài)時(shí),需要對(duì)凍結(jié)進(jìn)行清除,強(qiáng)制讓線程恢復(fù)到運(yùn)行狀態(tài)中來(lái),這樣就可以操作標(biāo)記讓線程結(jié)束Thread類中提供了interrupt方法*/class StopThread implements Runnable{ boolean flag=true; public synchronized void run() { while(flag){ try { wait(); } catch (InterruptedException e) {System.out.println(Thread.currentThread().getName()+"....Exception"); // flag=false; }System.out.println(Thread.currentThread().getName()+"....run"); } } public void changeFlag(){ flag=false; }}public class StopThreadDemo { public static void main(String[] args) { StopThread t=new StopThread(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); int num=0; while(true){ if(num++==60){ //t.changeFlag(); t1.interrupt(); t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"...."+num); } }}

運(yùn)行結(jié)果: 運(yùn)行結(jié)果,interrupt強(qiáng)制清除凍結(jié) 4)消除凍結(jié) class StopThread implements Runnable { boolean flag=true; public synchronized void run() { while(flag){ try { wait(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+”….Exception”); // flag=false; } System.out.println(Thread.currentThread().getName()+”….run”); } } public void changeFlag(){ flag=false; } } public class StopThreadDemo { public static void main(String[] args) { StopThread t=new StopThread();

Thread t1=new Thread(t);Thread t2=new Thread(t);t1.start();t2.start();int num=0;while(true){ if(num++==60){ //t.changeFlag(); t1.interrupt(); t2.interrupt(); break; }

System.out.println(Thread.currentThread().getName()+”….”+num); } } } 4)

class StopThread implements Runnable{ boolean flag=true; public synchronized void run() { while(flag){ try { wait(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+"....Exception"); flag=false; } System.out.println(Thread.currentThread().getName()+"....run"); } } public void changeFlag(){ flag=false; }}public class StopThreadDemo { public static void main(String[] args) { StopThread t=new StopThread(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); int num=0; while(true){ if(num++==60){ //t.changeFlag(); //t1.interrupt(); //t2.interrupt(); break; }System.out.println(Thread.currentThread().getName()+"...."+num); } }}

2.守護(hù)線程 setDaemon 1)public final void setDaemon(boolean on) 將該線程標(biāo)記為守護(hù)線程或用戶線程。當(dāng)正在運(yùn)行的線程都是守護(hù)線程時(shí),Java 虛擬機(jī)退出。 該方法必須在啟動(dòng)線程前調(diào)用。 2)將上面的主函數(shù)代碼變?yōu)橄旅娲a

public class StopThreadDemo { public static void main(String[] args) { StopThread t=new StopThread(); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.setDaemon(true); t2.setDaemon(true); t1.start(); t2.start(); int num=0; while(true){ if(num++==60){ //t.changeFlag(); //t1.interrupt(); //t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"...."+num); } System.out.println("over"); }}

3)程序中有三個(gè)線程:主線程,開啟的t1,t2線程 t1,t2是守護(hù)線程;只要主函數(shù)結(jié)束,守護(hù)線程便結(jié)束 3.join public final void join() throws InterruptedException 等待該線程終止 拋出: InterruptedException - 如果任何線程中斷了當(dāng)前線程。當(dāng)拋出該異常時(shí),當(dāng)前線程的中斷狀態(tài)被清除。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 凤庆县| 石林| 拜城县| 共和县| 洛川县| 文登市| 繁峙县| 贵港市| 沾益县| 池州市| 开化县| 玉山县| 昌图县| 连云港市| 上蔡县| 忻城县| 蒙阴县| 富平县| 寿宁县| 防城港市| 嵊泗县| 赣榆县| 榕江县| 宜兰市| 通州区| 星子县| 肇源县| 灌云县| 民勤县| 榕江县| 密山市| 西盟| 怀远县| 绿春县| 河曲县| 当阳市| 东宁县| 汝城县| 景洪市| 东宁县| 徐水县|