線程(java課堂筆記)

來源:互聯網
上載者:User

標籤:預設   art   ==   一段   getname   system   dem   線程的生命週期   ++   

1.兩種方式的差異2.線程的生命週期3.線程式控制制(線程的方法)4.線程同步5.線程同步鎖一、 兩種方式的差異A extends Thread :簡單不能再繼承其他類了(Java單繼承)同份資源不共用B implements Runnable:( 推薦) )多個線程共用一個目標資源,適合多執行緒同一份資源。該類還可以繼承其他類,也可以實現其他介面。二、 線程的生命週期建立:當程式使用new建立一個線程後,該線程處於建立狀態,此時他和其他java對象一樣,僅僅由Java虛擬機器為其分配記憶體並初始化成員變數值。【 Thread r = new Thread()】就緒:當線程對象調用start()方法後,該線程處於就緒狀態,線程計入線程隊列排隊,此時該狀態線程並未開始執行,它僅表示可以運行了。至於該線程何時運行,取決於JVM線程調度器的調度。【 r.start() 】運行:若處於就緒狀態的線程獲得了CPU,開始執行run()線程執行體,該線程處於執行狀態。阻塞:線程運行過程中需要被中斷,目的是是其他的線程獲得執行的機會。該狀態就會進入阻塞狀態。注意:阻塞狀態不能直接轉成運行狀態,阻塞狀態只能重新進入就緒狀態。死亡:run()執行完成,線程正常結束;線程拋出未捕獲的Exception或Error;調用線程的stop()。(易導致死結,不推薦)注意:主線程結束後,其他線程不受其影響,不會隨之結束;一旦子線程啟動起來後,就擁有和主線程相等地位,不受主線程影響。例子:class MyThread implements Runnable {  public void run() {    for (int i = 0; i < 200;i++) {      System.out.println(i);    }  }}public class MyThreadDemo {  public static void main(String[] args) {    for (int i = 0; i < 10;i++) {      if(i == 5){        MyThread t = new MyThread();        new Thread(t).start();      }      System.out.println("main" + i);    }  }}測試線程是否活著,可用線程對象的isAlive()方法。當線程處於就緒,運行,阻塞狀態返回true。當線程處於建立和死亡狀態,返回false。已死亡的線程是不可能通過start()方法喚醒線程的。否則引發IllegalThreadStateException異常;public class DieThreadDemo {  public static void main(String[]args) {    DeadThread dt = new DeadThread();    for (int i = 0; i < 100; i++) {      Thread mainThread =Thread.currentThread();//獲得當前線程(Main線程)      System.out.println(mainThread.getName()+ "--" + i);      System.out.println("------>"+mainThread.isAlive());      if (i == 10) {        dt.start();      }    }    if (!dt.isAlive()) {      dt.start();    }  }}class DeadThread extends Thread {  public void run() {    for (int i = 0; i < 50; i++) {      System.out.println(getName() +"--" + i);    }  }}三、線程式控制制Join()方法:等待該線程終止。join 方法:調用join方法的線程對象強制運行,該線程強制運行期間,其他線程無法運行,必須等到該線程結束後其他線程才可以運行。有人也把這種方式成為聯合線程join方法的重載方法:join(long millis):join(long millis,int nanos):通常很少使用第三個方法:程式無須精確到一納秒;電腦硬體和作業系統也無法精確到一納秒;public class JoinDemo {  public static void main(String[]args) throws Exception {    Thread join = new Thread(newJoin(),"Join線程");    join.start();    int i = 0;    while(i < 500){      if(i == 100){        join.join();      }      System.out.println("Main -- > "+ i ++);    }  }}class Join implements Runnable {  public void run() {    int i = 0;    while(i< 200){      System.out.println(Thread.currentThread().getName() + "--" + i ++ );    }  }}setDaemon()方法後台線程:處於後台運行,任務是為其他線程提供服務。也稱為“守護線程”或“精靈線程”。JVM的記憶體回收就是典型的後台線程。特點:若所有的前台線程都死亡,後台線程自動死亡。設定後台線程:Thread對象setDaemon(true);setDaemon(true)必須在start()調用前。否則出現IllegalThreadStateException異常;前台線程建立的線程預設是前台線程;判斷是否是後台線程:使用Thread對象的isDaemon()方法;並且若且唯若建立線程是後台線程時,新線程才是後台線程。class Daemon extends Thread {  public void run() {    for (int i = 0; i < 10000; i++) {      System.out.println(getName() +"-" + i);    }  }}public class DaemonDemo {  public static void main(String[]args) {    Daemon d = new Daemon();    d.setDaemon(true);//把 d 線程設定成後台線程    d.start();    for (int i = 0; i < 5; i++) {      System.out.println(Thread.currentThread().getName()+"--" + i);    }  }}Sleep()線程休眠:讓執行的線程暫停一段時間,進入阻塞狀態。sleep(long milllis) throws InterruptedException:毫秒sleep(long millis,int nanos) throws InterruptedException:毫秒,納秒調用sleep()後,在指定時間段之內,該線程不會獲得執行的機會。public class SleepDemo {  public static void main(String[]args) {    for (int i = 10; i > 0; i--) {      System.out.println("還剩" + i);      try {        Thread.sleep(1000);      } catch (InterruptedException e){        e.printStackTrace();      }    }  }}四、線程優先順序每個線程都有優先順序,優先順序的高低只和線程獲得執行機會的次數多少有關。並非線程優先順序越高的就一定先執行,哪個線程的先運行取決於CPU的調度;預設情況下main線程具有普通的優先順序,而它建立的線程也具有普通優先順序。Thread對象的setPriority(int x)和getPriority()來設定和獲得優先順序。MAX_PRIORITY : 值是10MIN_PRIORITY : 值是1NORM_PRIORITY : 值是5(主方法預設優先順序)class Priority extends Thread{  public void run() {    for (int i = 0; i < 100; i++) {      System.out.println(getName()+",優先順序=" + getPriority() +"--"+ i);    }  }}public class PriorityDemo {  public static void main(String[]args) {    Thread.currentThread().setPriority(7);    for (int i = 0; i < 100; i++) {      if(i == 10){        Priority p1 = new Priority();        p1.setPriority(Thread.MAX_PRIORITY);        p1.start();      }      if(i == 15){        Priority p2 = new Priority();        p2.setPriority(Thread.MIN_PRIORITY);        p2.start();      }      System.out.println("main" + i);    }  }}Yield()方法線程禮讓:暫停當前正在執行的線程對象,並執行其他線程;Thread的靜態方法,可以是當前線程暫停,但是不會阻塞該線程,而是進入就緒狀態。所以完全有可能:某個線程調用了yield()之後,線程調度器又把他調度出來重新執行。class Yield implements Runnable {  public void run() {    for (int i = 0; i < 100; i++) {      System.out.println(Thread.currentThread().getName() + "--> " + i);      if (i % 2 == 0) {        Thread.yield();// 禮讓      }    }  }}public class YieldDemo {  public static void main(String[]args) {    Yield y = new Yield();    new Thread(y, "A").start();    new Thread(y, "C").start();  }}API 過時方法 -- 易死結, , 不推薦使用stop:終止線程馬上讓線程停止運行,並釋放該線程所持有的鎖,該操作無法保證對象的內部狀態正確;suspend:掛起線程使線程進入“阻塞”狀態,該狀態下CPU不會分給線程時間片,進入這個狀態可以用來暫停一個線程的運行,在被resume方法調用前,不可用.如果要suspend的目標線程對一個重要的系統資源持有鎖,那麼沒任何線程可以使用這個資源直到要suspend的目標線程被resumed。resume:恢複線程恢複被suspend方法掛起的線程Java2開始已經廢棄了suspend()和resume()方法,因為使用這兩個方法可能會產生死結,所以應該使用同步對象調用wait()和notify()的機制來代替suspend()和resume()進行線程式控制制。五、線程的安全性問題導致安全問題的出現的原因:多個線程訪問出現延遲。線程隨機性。註:安全執行緒問題在理想狀態下,不容易出現,但一旦出現對軟體的影響是非常大的。我們可以通過Thread.sleep(long time)方法來簡單類比延遲情況。六、線程同步當多個線程訪問同一份資料的時候,很容易出現安全執行緒的問題。讓多個操作在同一個時間段內只能有一個線程進行,其它線程要等到該線程完成後才可以繼續執行。經典的案例: 銀行取錢使用者輸入取款金額;系統判斷餘額是否大於取款金額若餘額大於取款金額,取款成功;若餘額小於取款金額,取款失敗。例子分析:賬戶類:Account欄位balance表示餘額取錢類:DrawMoney 線程類欄位a表示賬戶對象,money表示需要取的金額;把取錢行為放線上程體裡面;提示:public void run(){  if(c.getBlance() >= money){    System.out.println(getName()+",取走" + money);    Thread.sleep(100);    c.setBlance(c.getBlance()- money);    System.out.println("餘額= " +c.getBlance());  }else{    System.out.println(getName()+ "餘額不足,餘額"+ c.getBlance() +",需要取走" +money );  }}解決問題:方法一:當發生以上情況時,java給我們提供了同步代碼塊synchronized(obj){//obj表示同步監視器,是同一個同步對象/**.....TODO SOMETHING*/}方法二:synchronized 傳回值類型 方法名(參數列表){/**.....TODO SOMETHING*/}同步方法的同步監聽器其實的是 this/*** 帳號**/public class Account {/*** 餘額*/  private double blance;  public Account(double blance) {    this.blance = blance;  }  public double getBlance() {    return blance;  }  public void setBlance(double blance){    this.blance = blance;  }  public synchronized void draw(doubledrawMoney){    if(getBlance() >= drawMoney) {      System.out.println(Thread.currentThread().getName()+",取出" + drawMoney);      try {        Thread.sleep(1);      } catch (InterruptedException e){        e.printStackTrace();      }//修改餘額      setBlance(getBlance() -drawMoney);      System.out.println("餘額= " +getBlance());    }else{      System.out.println("對不起餘額不足");    }  }}/*** 取錢操作*/public class DrawThread extendsThread{/*** 帳號*/  private Account a;/*** 取的錢*/  public double drawMoney;  public DrawThread(String name,Account a,double drawMoney){    super(name);    this.a = a;    this.drawMoney = drawMoney;  }/*** 當多條線程修改同一個共用資源資料的時候,將會導致資料安全問題*/  public void run(){/*   synchronized (a) {      if(a.getBlance() >= drawMoney) {        System.out.println(getName()+",取出" +drawMoney);        try {          Thread.sleep(1);        } catch (InterruptedExceptione) {          e.printStackTrace();        }//修改餘額        a.setBlance(a.getBlance() -drawMoney);        System.out.println("餘額= " +a.getBlance());      }else{        System.out.println("對不起餘額不足");      }    }*/    a.draw(drawMoney);  }}以上內容是課堂筆記之後是今天作業:做一個售票的程式要求三個視窗,一共50張票,隨機售票,售完後求小明在每個視窗購票的幾率:

public class Dome {                         //主類
  public static void main(String[] args) {             //主方法
    Chuangkou c1 = new Chuangkou("視窗一");
    Chuangkou c2 = new Chuangkou("視窗二");
    Chuangkou c3 = new Chuangkou("視窗三");
    Thread t1 = new Thread(c1);               //建立三個線程
    Thread t2 = new Thread(c2);
    Thread t3 = new Thread(c3);
    t1.start();                         //三個線程同時運行
    t2.start();
    t3.start();
  }
}

public class Piao{                        //用來統計票數  
  public static String name = "目前只有這一種票";
  public static int piao = 1;
}

public class Chuangkou implements Runnable{           //視窗類別
  public String name;
  static int a = 0;                        //定義三個靜態變數用來統計每個視窗一共賣的票
  static int b = 0;
  static int c = 0;
  public Chuangkou(String name) {               //有參構造器
    this.name = name;
  }
  public void run(){                        //run方法
    while(Piao.piao<49){                    //如果票數等於49就停止
      try {
        Thread.sleep(1/10);                //經測試睡眠1/10的時間最有利於每個視窗的售票率
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      synchronized(Piao.name){                //同步,防止多個線程同時運行
        System.out.println(name+"賣出了第 "+Piao.piao+++"票");
      }
      switch(name){                      //統計視窗票數
        case "視窗一":a+=1;break;
        case "視窗二":b+=1;break;
        case "視窗三":c+=1;break;
      }
    }
    System.out.println(name+"售罄");
    if(Piao.piao == 50){                      //計算出小明購票幾率
      System.out.println("小明買視窗一的票的機率為"+(a/50.0));
      System.out.println("小明買視窗二的票的機率為"+(b/50.0));
      System.out.println("小明買視窗三的票的機率為"+(c/50.0));
    }

  }
}

目前這個作業還有問題,不知為什麼小明的效率有時會出現兩次,有時不出現,希望大神指導一下。

線程(java課堂筆記)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.