進(jìn)程是應(yīng)用程序的執(zhí)行實(shí)例。
進(jìn)程是程序的一次動(dòng)態(tài)執(zhí)行過(guò)程,它經(jīng)歷了從代碼加載、執(zhí)行到執(zhí)行完畢的一個(gè)完整過(guò)程,這個(gè)過(guò)程也是進(jìn)程本身從產(chǎn)生、發(fā)展到最終消亡的過(guò)程特征:動(dòng)態(tài)產(chǎn)生,動(dòng)態(tài)消亡。進(jìn)程是并發(fā)性的。進(jìn)程獨(dú)立性。是一個(gè)獨(dú)立運(yùn)行的基本單位,也是系統(tǒng)分配資源和調(diào)度的基本單位1.2、線程多線程是實(shí)現(xiàn)并發(fā)機(jī)制的一種有效手段。進(jìn)程和線程一樣,都是實(shí)現(xiàn)并發(fā)的一個(gè)基本單位線程:進(jìn)程內(nèi)部的一個(gè)執(zhí)行單元,它是程序中一個(gè)單一的順序控制流程特點(diǎn):使用步驟:
定義一個(gè)線程----創(chuàng)建線程的實(shí)例--啟動(dòng)線程--終止線程
/** * 繼承Thread類重寫run方法 * */public class MyThead1 extends Thread { PRivate int count; @Override public void run() { System.out.println("=======線程啟動(dòng)了======="); while(this.count<100){ count++; } System.out.println("count最終的值:"+count); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
測(cè)試類
/** * 測(cè)試類 * MyTheadDemo * 繼承Thread類創(chuàng)建線程 * 1.繼承Thread類 * 2.重寫run方法 * 3.實(shí)例化線程類對(duì)象 * 4.調(diào)用start方法啟動(dòng)線程 * * 繼承Thread類存在問(wèn)題 * Java中是單繼承的,線程類不能繼承其它的類 * * 解決辦法:實(shí)現(xiàn)Runnable接口 * */public class MyTheadDemo1 { public static void main(String[] args) { //實(shí)例化線程類對(duì)象 MyThead1 myThead1=new MyThead1(); //啟動(dòng)線程 myThead1.start(); /* * start方法的作用 * 該方法公使操作系統(tǒng)初始化一個(gè)新的線程 * 由這個(gè)新線程來(lái)執(zhí)行線程對(duì)象的Run方法 */ }}2.2、實(shí)現(xiàn)Runnable接口(推薦使用,使用接口可以解決Java中單繼承的問(wèn)題)在Java中也可以通過(guò)實(shí)現(xiàn)Runnable接口的方式實(shí)現(xiàn)多線程,Runnable接口中只定義了一個(gè)抽象方法:public void run() ;
/** * 實(shí)現(xiàn)Runnable接口 * */public class MyRunnable implements Runnable { private int count; @Override public void run() { System.out.println("=======線程啟動(dòng)了======="); while(this.count<100){ count++; } System.out.println("count最終的值:"+count); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
測(cè)試類
/** * 測(cè)試類 * MyRunnable * 實(shí)現(xiàn)Runnable接口創(chuàng)建線程 * 1.實(shí)現(xiàn)Runnable接口 * 2.實(shí)現(xiàn)run方法 * 3.實(shí)例化線程類對(duì)象 * 4.創(chuàng)建Thread類實(shí)例對(duì)象,并將實(shí)例化的線程對(duì)象傳入 * 5.調(diào)用Thread類實(shí)例對(duì)象的start方法啟動(dòng)線程 * */public class MyRunnableDemo { public static void main(String[] args) { //實(shí)例化線程類對(duì)象 Runnable myRunnable=new MyRunnable(); Thread thread=new Thread(myRunnable); //或者Thread thread=new Thread(new MyRunnable()); //啟動(dòng)線程 thread.start(); }}2.3、啟動(dòng)線程
/** * 實(shí)現(xiàn)Runnable接口 * */public class MyRunnable implements Runnable { private int count; @Override public void run() { count++; System.out.println("count最終的值:"+count); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
測(cè)試類
/** * 測(cè)試類 * MyRunnable * 實(shí)現(xiàn)Runnable接口創(chuàng)建線程 * 1.實(shí)現(xiàn)Runnable接口 * 2.實(shí)現(xiàn)run方法 * 3.實(shí)例化線程類對(duì)象 * 4.創(chuàng)建Thread類實(shí)例對(duì)象,并將實(shí)例化的線程對(duì)象傳入 * 5.調(diào)用Thread類實(shí)例對(duì)象的start方法啟動(dòng)線程 * */public class MyRunnableDemo { public static void main(String[] args) { //實(shí)例化線程類對(duì)象 Runnable myRunnable=new MyRunnable(); Thread thread=new Thread(myRunnable); Thread thread2=new Thread(myRunnable); //或者Thread thread=new Thread(new MyRunnable()); //啟動(dòng)線程 System.out.println("線程1啟動(dòng)"); thread.start(); System.out.println("線程2啟動(dòng)"); thread2.start(); }}
結(jié)果:
線程1啟動(dòng)線程2啟動(dòng)count最終的值:1count最終的值:2
再看下thread方式
/** * 繼承Thread類重寫run方法 * */public class MyThead1 extends Thread { private int count; @Override public void run() { count++; System.out.println("count最終的值:"+count); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
/** * 測(cè)試類 * MyTheadDemo * 實(shí)現(xiàn)Runnable接口創(chuàng)建純種 * 1.實(shí)現(xiàn)Runnable接口 * 2.重寫run方法 * 3.實(shí)例化線程類對(duì)象 * 4.調(diào)用start方法啟動(dòng)線程 * * 繼承Thread類存在問(wèn)題 * Java中是單繼承的,線程類不能繼承其它的類 * * 解決辦法:實(shí)現(xiàn)Runnable接口 * */public class MyTheadDemo1 { public static void main(String[] args) { //實(shí)例化線程類對(duì)象 MyThead1 myThead1=new MyThead1(); MyThead1 myThead2=new MyThead1(); //啟動(dòng)線程 System.out.println("線程1啟動(dòng)"); myThead1.start(); System.out.println("線程2啟動(dòng)"); myThead2.start(); /* * start方法的作用 * 該方法公使操作系統(tǒng)初始化一個(gè)新的線程 * 由這個(gè)新線程來(lái)執(zhí)行線程對(duì)象的Run方法 */ }}
結(jié)果:
線程1啟動(dòng)線程2啟動(dòng)count最終的值:1count最終的值:1
No. | 方法名稱 | 類型 | 描述 |
1 | public Thread(Runnable target) | 構(gòu)造 | 接收Runnable接口子類對(duì)象,實(shí)例化Thread對(duì)象 |
2 | public Thread(Runnable target,String name) | 構(gòu)造 | 接收Runnable接口子類對(duì)象,實(shí)例化Thread對(duì)象,并設(shè)置線程名稱 |
3 | public Thread(String name) | 構(gòu)造 | 實(shí)例化Thread對(duì)象,并設(shè)置線程名稱 |
4 | public static Thread currentThread() | 普通 | 返回目前正在執(zhí)行的線程 |
5 | public final String getName() | 普通 | 返回線程的名稱 |
6 | public final int getPriority() | 普通 | 發(fā)揮線程的優(yōu)先級(jí) |
7 | public boolean isInterrupted() | 普通 | 判斷目前線程是否被中斷,如果是,返回true,否則返回false |
8 | public final boolean isAlive() | 普通 | 判斷線程是否在活動(dòng),如果是,返回true,否則返回false |
9 | public final void join() throws InterruptedException | 普通 | 等待線程死亡 |
10 | public final synchronized void join(long millis) throws InterruptedException | 普通 | 等待millis毫秒后,線程死亡 |
11 | public void run() | 普通 | 執(zhí)行線程 |
12 | public final void setName(String name) | 普通 | 設(shè)定線程名稱 |
13 | public final void setPriority(int newPriority) | 普通 | 設(shè)定線程的優(yōu)先值 |
14 | public static void sleep(long millis) throws InterruptedException | 普通 | 使目前正在執(zhí)行的線程休眠millis毫秒 |
15 | public void start() | 普通 | 開始執(zhí)行線程 |
16 | public static void yield() | 普通 | 將目前正在執(zhí)行的線程暫停,允許其它線程執(zhí)行 |
17 | public final void setDaemon(boolean on) | 普通 | 將一個(gè)線程設(shè)置成后臺(tái)運(yùn)行 |
18 | public final void setPriority(int newPriority) | 普通 | 更改線程的優(yōu)先級(jí) |
作用:阻塞指定的線程等到另一個(gè)線程完成以后,再繼續(xù)執(zhí)行
package thead;/** * 實(shí)現(xiàn)join方法 * 1.join的線程運(yùn)行完成后,才會(huì)繼承運(yùn)行當(dāng)前線程 * 2.join之前要先啟動(dòng)線程start方法 * */public class JoinRunnable implements Runnable { @Override public void run() { for (int i = 0; i <5; i++) { System.out.println(Thread.currentThread().getName()+" 第"+i+"次"); } } public static void main(String[] args) { //主線程 for (int i = 0; i <10; i++) { if(i==5){ Thread thread=new Thread(new JoinRunnable());; thread.setName("半路切入的線程:"); try { //啟動(dòng)線程 thread.start(); //半路加入線程 thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+" 第"+i+"次"); } }}
結(jié)果:
main 第0次main 第1次main 第2次main 第3次main 第4次半路切入的線程: 第0次半路切入的線程: 第1次半路切入的線程: 第2次半路切入的線程: 第3次半路切入的線程: 第4次main 第5次main 第6次main 第7次main 第8次main 第9次5.2、sleep()阻塞當(dāng)前線程,當(dāng)前等待的線程將獲得機(jī)會(huì)
調(diào)用sleep方法后,,當(dāng)前線程會(huì)被扶起(暫停執(zhí)行)當(dāng)前線程會(huì)釋放資源
package thead;public class SleepRunnable implements Runnable { @Override public void run() { try { for (int i = 0; i < 10; i++) { //每一秒執(zhí)行一次 Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+i); } } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread sleepThread=new Thread(new SleepRunnable()); sleepThread.setName("等待中的線程"); sleepThread.start(); for (int i = 0; i < 10; i++) { if(i==5){ try { //主線程=等5秒 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+i); } } }
結(jié)果:
main0main1main2main3main4等待中的線程0等待中的線程1等待中的線程2等待中的線程3main5main6main7main8main9等待中的線程4等待中的線程5等待中的線程6等待中的線程7等待中的線程8等待中的線程95.3、yield()方法
將當(dāng)前線程轉(zhuǎn)入可運(yùn)行狀態(tài),
package yield;/** * 線程一 * */public class MyThread1 implements Runnable { @Override public void run() { for (int i = 0; i <10; i++) { Thread.yield(); System.out.println(Thread.currentThread().getName()+":"+i); } }}package yield;/** * 線程二 * */public class MyThread2 implements Runnable { @Override public void run() { for (int i = 0; i <10; i++) { Thread.yield(); System.out.println(Thread.currentThread().getName()+": "+i); } }}package yield;/** * yield方法使用 *2個(gè)線程搶占方式 */public class Test { public static void main(String[] args) { Thread myThread1=new Thread(new MyThread1()); myThread1.setName("線程1"); Thread myThread2=new Thread(new MyThread2()); myThread2.setName("線程2"); //同時(shí)啟動(dòng)2個(gè)線程 myThread1.start(); myThread2.start(); }}
結(jié)果:
線程2: 0線程1:0線程2: 1線程1:1線程2: 2線程1:2線程2: 3線程1:3線程1:4線程2: 4線程1:5線程1:6線程1:7線程1:8線程1:9線程2: 5線程2: 6線程2: 7線程2: 8線程2: 9
sleep()和yield()方法比較
將線程設(shè)置 為后臺(tái)線程(守護(hù)線程)。
只能在線程啟動(dòng)之前設(shè)置.
package thead;public class Daemon implements Runnable { @Override public void run() { for (int i = 0; i <10; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } public static void main(String[] args) { Thread daemon=new Thread(new Daemon()); daemon.setName("后臺(tái)線程"); // 設(shè)置為后臺(tái)線程 daemon.setDaemon(true); daemon.start(); for (int i = 0; i <10; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } }}六、同步一個(gè)多線程的程序,如果是通過(guò)Runnable接口實(shí)現(xiàn)的,則意味著類中的屬性將被多個(gè)線程共享,那么這樣一來(lái)就會(huì)造成一種問(wèn)題,如果這多個(gè)線程要操作同一資源的時(shí)候就有可能出現(xiàn)資源的同步問(wèn)題。例如:以之前的賣票程序來(lái)講,如果多個(gè)線程同時(shí)操作的時(shí)候就有可能出現(xiàn)賣出票為負(fù)數(shù)的問(wèn)題。問(wèn)題的解決如果想解決這樣的問(wèn)題,就必須使用同步,所謂的同步就是指多個(gè)操作在同一個(gè)時(shí)間段內(nèi)只能有一個(gè)線程進(jìn)行,其他線程要等待此線程完成之后才可以繼續(xù)執(zhí)行解決資源共享的同步操作,可以使用同步代碼塊和同步方法兩種方式完成同步代碼塊在代碼塊上加上“synchronized”關(guān)鍵字的話,則此代碼塊就稱為同步代碼塊。同步方法除了可以將需要的代碼設(shè)置成同步代碼塊之外,也可以使用synchronized關(guān)鍵字將一個(gè)方法聲明成同步方法。同步方法定義格式:synchronized 方法返回值 方法名稱(參數(shù)列表){}6.1、簡(jiǎn)單例子
同一賬戶2個(gè)人同時(shí)取款
package demo;public class Account { //余額 private int balance=500; //檢查余額 public int getBalance() { return balance; } //取款 public void withDraw(int amount){ balance=balance-amount; } public void setBalance(int balance) { this.balance = balance; } }package demo;public class TestAccount implements Runnable{ private Account account=new Account(); @Override public void run() { for (int i = 0; i <5; i++) { //一次取走100 makeWithDraw(100); if(account.getBalance()<0){ System.out.println("賬戶透支了!!!!!"); } } } //取款參數(shù) 同步方法 private synchronized void makeWithDraw(int amount){ if(account.getBalance()>=amount){ //當(dāng)前余額是否足夠可以取款 System.out.println(Thread.currentThread().getName()+" 準(zhǔn)備取款"); try { //0.5秒后取款 Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //完成取款 account.withDraw(amount); System.out.println(Thread.currentThread().getName()+" 完成取款,當(dāng)前余額為: "+account.getBalance()); }else{ //如果余額不足不能取款 System.out.println(Thread.currentThread().getName()+" 余額不足以支付當(dāng)前取款, 余額為: " +account.getBalance()); } } }
測(cè)試類
package demo;/** * 如果一個(gè)資源被多個(gè)線程使用,不上鎖就會(huì)造成讀取嚴(yán)重錯(cuò)誤 * 如果想讓當(dāng)前資源被一個(gè)線程使用時(shí),不會(huì)受到其他純種的影響,應(yīng)該給當(dāng)前資源上鎖 * Java中使用sychronized關(guān)鍵字保證數(shù)據(jù)同步 * */public class Test { public static void main(String[] args) { //創(chuàng)建線程類的實(shí)例 TestAccount ta=new TestAccount(); //創(chuàng)建線程 Thread thread1=new Thread(ta); thread1.setName("張三"); Thread thread2=new Thread(ta); thread2.setName("張三的妻子"); //啟動(dòng)線程 thread1.start(); thread2.start(); }}
上面是同步方法
下面是同步代碼塊
package demo;public class TestAccount implements Runnable{ private Account account=new Account(); @Override public void run() { for (int i = 0; i <5; i++) { //一次取走100 makeWithDraw(100); if(account.getBalance()<0){ System.out.println("賬戶透支了!!!!!"); } } } //取款參數(shù) private void makeWithDraw(int amount){ //同步代碼塊 synchronized (account){ if(account.getBalance()>=amount){ //當(dāng)前余額是否足夠可以取款 System.out.println(Thread.currentThread().getName()+" 準(zhǔn)備取款"); try { //0.5秒后取款 Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //完成取款 account.withDraw(amount); System.out.println(Thread.currentThread().getName()+" 完成取款,當(dāng)前余額為: "+account.getBalance()); }else{ //如果余額不足不能取款 System.out.println(Thread.currentThread().getName()+" 余額不足以支付當(dāng)前取款, 余額為: " +account.getBalance()); } } } }七、線程間通信的實(shí)現(xiàn)
以上3個(gè)方法只能在同步方式或者同步代碼塊中使用
wait()方法:會(huì)掛起當(dāng)前的線程,并且釋放共享資源的鎖。當(dāng)前線程會(huì)從可運(yùn)行狀態(tài)轉(zhuǎn)為阻塞狀態(tài)直到調(diào)用了wait()方法所屬的那個(gè)對(duì)象的notify()方法或者notifyAll()方法.
notify()方法:可以喚醒因?yàn)檎{(diào)用wait()方法而被掛起的那個(gè)線程,并且使這個(gè)線程退出阻塞狀態(tài)進(jìn)入可運(yùn)行狀態(tài)
notifyAll()方法:可以喚醒因?yàn)樗姓{(diào)用wait()方法而被掛起的那個(gè)線程,并且使這些線程退出阻塞狀態(tài)進(jìn)入可運(yùn)行狀態(tài)
生產(chǎn)者和消費(fèi)者package com.pb;/** * 商品共享數(shù)據(jù) * */public class SharedData { private char c; private boolean idProducted=false;//信號(hào)量 //同步方法生產(chǎn)者生產(chǎn)產(chǎn)品的的方法 public synchronized void putSharedChar(char c){ //如果產(chǎn)品還沒(méi)有被消費(fèi),則生產(chǎn)都等待 if(idProducted){ try { System.out.println("消費(fèi)者還未消費(fèi),因此生產(chǎn)都停止生產(chǎn)"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.c=c; idProducted=true; //標(biāo)記已經(jīng)生產(chǎn) notify();//通知消費(fèi)都 System.out.println("生產(chǎn)者生產(chǎn)了產(chǎn)品"+c+",通知消費(fèi)者"); } //同步方法 消費(fèi)者消費(fèi)產(chǎn)品的的方法 public synchronized char getSharedChar(char c){ //如果產(chǎn)品還沒(méi)有被消費(fèi),則生產(chǎn)都等待 if(idProducted==false){ try { System.out.println("生產(chǎn)者還未生產(chǎn),消費(fèi)者停止消費(fèi)"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } idProducted=false; //標(biāo)記已經(jīng)消費(fèi) notify();//通知生產(chǎn)者 System.out.println("消費(fèi)者消費(fèi)了產(chǎn)品"+c+",通知生產(chǎn)者"); return this.c; }}
package com.pb;/** * 生產(chǎn)者 * */public class Producer implements Runnable { //共享數(shù)據(jù) private SharedData sharedData; public Producer(SharedData sharedData){ this.sharedData=sharedData; } @Override public void run() { for (char c = 'A'; c <= 'D'; c++) { try { Thread.sleep((int)Math.random()*3000); } catch (InterruptedException e) { e.printStackTrace(); } //將產(chǎn)品生產(chǎn)后,放入倉(cāng)庫(kù) sharedData.putSharedChar(c); } }}
package com.pb;/** * 消費(fèi)者 * */public class Consumer implements Runnable { //共享數(shù)據(jù) private SharedData sharedData; public Consumer(SharedData sharedData){ this.sharedData=sharedData; } @Override public void run() { char ch = 0; do { try { Thread.sleep((int)Math.random()*3000); } catch (InterruptedException e) { e.printStackTrace(); } //從倉(cāng)庫(kù)中取中產(chǎn)品 ch=sharedData.getSharedChar(ch); } while (ch!='D'); }}
測(cè)試類
package com.pb;public class CommunicationDemo { public static void main(String[] args) { //共享資源,產(chǎn)品 SharedData sharedData=new SharedData(); Thread producer=new Thread(new Producer(sharedData)); Thread consumer=new Thread(new Consumer(sharedData)); //啟動(dòng)線程 consumer.start(); producer.start(); }}
結(jié)果:
生產(chǎn)者還未生產(chǎn),消費(fèi)者停止消費(fèi)生產(chǎn)者生產(chǎn)了產(chǎn)品A,通知消費(fèi)者消費(fèi)者消費(fèi)了產(chǎn)品A,通知生產(chǎn)者生產(chǎn)者生產(chǎn)了產(chǎn)品B,通知消費(fèi)者生產(chǎn)者還未生產(chǎn),消費(fèi)者停止消費(fèi)生產(chǎn)者生產(chǎn)了產(chǎn)品C,通知消費(fèi)者消費(fèi)者消費(fèi)了產(chǎn)品B,通知生產(chǎn)者生產(chǎn)者生產(chǎn)了產(chǎn)品D,通知消費(fèi)者消費(fèi)者消費(fèi)了產(chǎn)品C,通知生產(chǎn)者
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注