黑馬程式員—java基礎——————多線程通訊

來源:互聯網
上載者:User

線程間通訊:其實就是多個線程在操作同一個資源,但是操作的動作不同。

class Res {  

    private String name;  

    private String sex;  

    private  boolean flag = false;

    public synchronized void set(String name,String sex)

    {

        if(r.flag)     

          try{r.wait();}catch(Exception e){}    

        this.name = name;

        this.sex = sex;

        flag = true;    

        this.notify();   

    }

     public synchronized void out()  

    {

        if(r.flag)    

          try{r.wait();}catch(Exception e){}   

        System.out.println(name+"........"+sex);

        flag = false;   

        this.notify();  

     }

}

class Input implements Runnable {  

    private Res r ;  

    Input(Res r)  {   

        this.r = r;  

    }  

    public void run()  {   

        int x = 0;   

        while(true)   {    

           if(x==0)          

              r.set("mike","man");     

           else    

              r.set("麗麗","女女女女女");     

           x = (x+1)%2;     

        }  

    }

}

class Output implements Runnable {  

      private Res r ;    

      Output(Res r)  {   

          this.r = r;  

      }  

      public void run()  {   

          while(true)   {    

              r.out();

          }  

      }

}

class  InputOutputDemo {  

      public static void main(String[] args)  {   

            Res r = new Res();

             new Thread(new Input(r)).start();

             new Thread(new Output(r)).start(); 

      }

}

 wait();     notify();     notifyAll();都使用在同步中,因為要對持有監視器(鎖)的線程操作。所以要使用在同步中,因為只有同步才具有鎖。

    為什麼這些操作線程的方法要定義Object類中呢?因為這些方法在操作同步中線程時,都必須要標識它們所操作線程只有的鎖,只有同一個鎖上的被等待線程,可以

      被同一個鎖notify喚醒。不可以對不同鎖中的線程進行喚醒。也就是說,等待和喚醒必須是同一個鎖。而鎖可以是任意對象,所以可以被任意對象調用的方法定

      義Object類中。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

生產者和消費者的例子

    對於多個生產者和消費者。為什麼要定義while判斷標記。原因:讓被喚醒的線程再一次判斷標記。

    為什麼定義notifyAll,因為需要喚醒對方線程。因為只用notify,容易出現只喚醒本方線程的情況。導致程式中的所有線程都等待。

class ProducerConsumerDemo {  

     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(pro);   

        Thread t3 = new Thread(con);   

        Thread t4 = new Thread(con);

            t1.start();   

        t2.start();   

        t3.start();   

        t4.start();

     }

}

class Resource {  

    private String name;  

    private int count = 1;  

    private boolean flag = false;    

    public synchronized void set(String name)  {   

        while(flag)    

            try{this.wait();}catch(Exception e){}

        //t1(放棄資格)  t2(擷取資格)   

        this.name = name+""+count++;

                  System.out.println(Thread.currentThread().getName()+"...生產者.."+this.name);    

              flag = true;    

              condition_con.signal();   //通過指定就可以避免喚醒的時候吧己方喚醒,這也就不用signalALL(); 和notifyAll();(已經被替代)

          }   

          finally   {    

              lock.unlock();//釋放鎖的動作一定要執行。   

          }  

      }

       //  t3   t4   

      public  void out()throws InterruptedException  {   

          lock.lock();   

          try   {    

            while(!flag)     

            condition_con.await();    1.5新特性:通過指定就可以針對值讓己方等待,代替了wait();

            System.out.println(Thread.currentThread().getName()+"...消費者........."+this.name);    

            flag = false;    

            condition_pro.signal();   //通過指定就可以避免喚醒的時候吧己方喚醒,這也就不用signalALL(); 和notifyAll();(已經被替代)

          }   

          finally   {    

            lock.unlock();   

          }     

      }

}

class Producer implements Runnable {  

      private Resource res;

        Producer(Resource res)  {   

          this.res = res;  

      }  

      public void run()  {   

          while(true)   {    

             try    {     

                res.set("+商品+");    

             }    catch (InterruptedException e)    {    }       

          }  

      }

}

class Consumer implements Runnable {  

      private Resource res;

        Consumer(Resource res)  {   

          this.res = res;  

      }  

      public void run()  {   

          while(true)   {    

             try    {     

                res.out();      

             }    catch (InterruptedException e)    {    }   

          }  

      }

}

    JDK1.5 中提供了多線程升級解決方案。將同步Synchronized替換成現實Lock操作。將Object中的wait,notify notifyAll,替換了Condition對象。該對象可

        以Lock鎖 進行擷取。該樣本中,實現了本方只喚醒對方操作。

停止線程

      如何停止線程?:只有一種,run方法結束。開啟多線程運行,運行代碼通常是迴圈結構。只要控制住迴圈,就可以讓run方法結束,也就是線程結束。

          特殊情況:當線程處於了凍結狀態。就不會讀取到標記。那麼線程就不會結束。

          當沒有指定的方式讓凍結的線程恢複到運行狀態是,這時需要對凍結進行清除。強制讓線程恢複到運行狀態中來。這樣就可以操作標記讓線程結束。Thread

        類提供該方法 interrupt();

 

class StopThread implements Runnable {  

      private boolean flag =true;  

      public synchronizede void run()  {   

          while(flag)   {        //將flag置為false就可以控制迴圈了

              try{

                  wait();

              }

              catch(InterruppedException e)

              {

                System.out.println(Thread.currentThread().getName()+"....Exception");   

                flag = false; //代替了下面的changeFlag();

              }

              System.out.println(Thread.currentThread().getName()+"....run");  

          }  

      }  

      public void changeFlag()  {   

          flag = false;  

      }

}

class  StopThreadDemo {  

      public static void main(String[] args)  {   

          StopThread st = new StopThread();      

          Thread t1 = new Thread(st);   

          Thread t2 = new Thread(st);

            t1.setDaemon(true);   //守護線程,要線上程前調用,只要前台線程一結束,守護線程就自動結束了,藍色字型就去掉了沒用了

          t2.setDaemon(true);   

          t1.start();   

          t2.start();

            int num = 0;

            while(true)   {    

              if(num++ == 60)    {     

                  st.changeFlag();     

                  //t1.interrupt();     //對凍結進行清除。強制讓線程恢複到運行狀態中來

                  //t2.interrupt();     

                  break;    

              }    

              System.out.println(Thread.currentThread().getName()+"......."+num);   

          }   

          System.out.println("over");  

      }

}

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

join: 當A線程執行到了B線程的.join()方法時,A就會等待。等B線程都執行完,A才會執行。join可以用來臨時加入線程執行。

class Demo implements Runnable {  

      public void run()  {   

          for(int x=0; x<70; x++)   {    

              System.out.println(Thread.currentThread().toString()+"....."+x);    

              Thread.yield();   

          }  

      }

}

class  JoinDemo {  

      public static void main(String[] args) throws Exception  {   

          Demo d = new Demo();   

          Thread t1 = new Thread(d);   

          Thread t2 = new Thread(d);   

          t1.start();      

          //t1.setPriority(Thread.MAX_PRIORITY);

           t2.start();

           //t1.join();

           for(int x=0; x<80; x++)   {    

              //System.out.println("main....."+x);   

           }   

           System.out.println("over");  

     }

}

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

class MyThread extends Thread{  

      public void run(){   

          try {    

            Thread.currentThread().sleep(3000);   

          } catch (InterruptedException e) {   }   

          System.out.println("MyThread running");  

      }

}

public class ThreadTest{  

      public static void main(String argv[]) {   

          MyThread t = new MyThread();   

          t.run();   

          t.start();   

          System.out.println("Thread Test");   

      }

}

程式碼分析過程:

MyThread t = new MyThread(); 建立了一個線程。

    t.run();

      調用MyThread對象的run方法。這是只有一個線程在運行就是主線程。當主線程執行到了run方法中的sleep(3000);時。這是主線程處於凍結狀態。程式並沒有任何

          執行。當3秒過後,主線程列印了  MyThread running。 run方法執行結束。

    t.start();

      開啟了t線程。有兩種可能情況。第一種,主線程在只執行了t.start()後,還具有執行權,繼續往下執行,列印了Thread Test。主線程結束。t線程擷取執行權,調用

          自己的run方法。然後執行的sleep(3000);凍結3秒。3秒後,列印MyThread running t線程結束,整個程式結束。

      第二種情況:主線程執行到t.start();開啟了t線程,t線程就直接擷取到了執行權。就調用自己的run方法。指定到sleep(3000).t線程凍結3秒,這是t線程就是釋放了

   執行權。那麼主線程開始執行列印了Thread Test,主線程結束。等到3秒後,t線程列印MyThread running ,然後t線程結束。程式結束。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.