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