多線程和Lambda表達(dá)式

7月20日知識點(diǎn)

今天的主要內(nèi)容——線程

  • 線程

    • 線程的基本概念

      • 線程與進(jìn)程的區(qū)別
    • 線程的兩種創(chuàng)建方式(掌握)

      • 注意線程兩種創(chuàng)建方式的區(qū)別

      • 內(nèi)部類實(shí)現(xiàn)線程創(chuàng)建

    • 線程的第三種創(chuàng)建方式——實(shí)現(xiàn)Callable接口

    • Thread類中的方法使用

      • getName()
      • setName()
      • currentthread()
      • sleep
      • join
      • wait
      • yield
      • setDaemon
    • 線程的同步(掌握)

      • 同步代碼塊

      • 同步方法

    • 多線程(線程安全問題)(掌握)

    • 線程的死鎖(了解)

    • 多線程和隊(duì)列實(shí)現(xiàn)買賣票(掌握)

  • Lambda表達(dá)式

    • lambda表達(dá)式的幾種方式
    • lambda表達(dá)式用途

線程

1. 線程的基本概念

  • image
  • 1.什么是線程

    • 線程是程序執(zhí)行的一條路徑, 一個(gè)進(jìn)程中可以包含多條線程
    • 多線程并發(fā)執(zhí)行可以提高程序的效率, 可以同時(shí)完成多項(xiàng)工作
  • 進(jìn)程:其實(shí)是一個(gè)靜態(tài)的概念
    * 我們平時(shí)所說的進(jìn)程開始執(zhí)行,指的是:進(jìn)程中主線程開始執(zhí)行了,即main方法開始執(zhí)行了

  • 計(jì)算機(jī)中實(shí)際運(yùn)行的都是線程。

  • 操作系統(tǒng)是支持多線程,多進(jìn)程的,系統(tǒng)是同時(shí)執(zhí)行多個(gè)線程的

  • CPU的執(zhí)行:交替執(zhí)行眾多線程,因?yàn)樗俣瓤欤砻嫔鲜峭瑫r(shí)執(zhí)行多個(gè)線程,其實(shí)不是的。

注:

① Java的線程是通過java.lang.Thread類來實(shí)現(xiàn)的

② VM啟動時(shí)會有一個(gè)主方法(main方法)所定義的線程

③ 可通過創(chuàng)建Thread的實(shí)例來創(chuàng)建新的線程

④ 每個(gè)線程都是通過某個(gè)特定的Thread對象所對應(yīng)的run方法來完成其操作的,方法run()稱為線程體

⑤ 通過調(diào)用Thread類中的start()方法來啟動一個(gè)線程。

2. 多線程(多線程并行和并發(fā)的區(qū)別)(了解)

  • 并行就是兩個(gè)任務(wù)同時(shí)運(yùn)行,就是甲任務(wù)進(jìn)行的同時(shí),乙任務(wù)也在進(jìn)行。(需要多核CPU)
  • 并發(fā)是指兩個(gè)任務(wù)都請求運(yùn)行,而處理器只能按受一個(gè)任務(wù),就把這兩個(gè)任務(wù)安排輪流進(jìn)行,由于時(shí)間間隔較短,使人感覺兩個(gè)任務(wù)都在運(yùn)行。
  • 比如我跟兩個(gè)網(wǎng)友聊天,左手操作一個(gè)電腦跟甲聊,同時(shí)右手用另一臺電腦跟乙聊天,這就叫并行。
  • 如果用一臺電腦我先給甲發(fā)個(gè)消息,然后立刻再給乙發(fā)消息,然后再跟甲聊,再跟乙聊。這就叫并發(fā)。

3. 多線程(Java程序運(yùn)行原理和JVM的啟動是多線程的嗎)(了解)

  • A:Java程序運(yùn)行原理

    • Java命令會啟動java虛擬機(jī),啟動JVM,等于啟動了一個(gè)應(yīng)用程序,也就是啟動了一個(gè)進(jìn)程。該進(jìn)程會自動啟動一個(gè) “主線程” ,然后主線程去調(diào)用某個(gè)類的 main 方法。
  • B:JVM的啟動是多線程的嗎

    • JVM啟動至少啟動了垃圾回收線程和主線程,所以是多線程的。

    • 運(yùn)行程序證明JVM的多線程

        public class TestJVMMultiThread {   
            public static void main(String[] args) {
                //創(chuàng)建垃圾對象觀察垃圾回收線程
                for(int i = 0;i < 100;i++) {
                    new Test();     
                }
                
                for(int i = 0;i < 100;i++) {
                    System.out.println("主線程在執(zhí)行");   
                }       
            }   
        }
        
        class Test{
            
            @Override
            public void finalize(){
                System.out.println("垃圾回收線程在執(zhí)行");
            }   
        }
      

4. 線程的兩種創(chuàng)建方式

image
image
image
image

3. 線程兩種創(chuàng)建方式程序

  • 創(chuàng)建線程程序1:

    image
    image
    • 用lambda表達(dá)式簡寫線程啟動過程

        public class TestLambda {
            public static void main(String[] args) {
                
                System.out.println("哈哈哈哈我在測試啊");
                
                Runnable runner = ()->{
                    StringBuffer s = new StringBuffer();
                    
                    for(int i= 0;i < 10;i++)
                        System.out.println(s.append("haha"));
                };
                
                new Thread(runner).start();  //注意:同一個(gè)線程不可以啟動多次
                
                System.out.println("任務(wù)完成");
            }   
        }
        /*
         *  在JDK1.8中輸出結(jié)果為:
         *  ------------------------------------------
         *  哈哈哈哈我在測試啊
            任務(wù)完成
            haha
            hahahaha
            hahahahahaha
            hahahahahahahaha
            hahahahahahahahahaha
            hahahahahahahahahahahaha
            hahahahahahahahahahahahahaha
            hahahahahahahahahahahahahahahaha
            hahahahahahahahahahahahahahahahahaha
            hahahahahahahahahahahahahahahahahahahaha
            ------------------------------------------
         * */
      
  • 創(chuàng)建線程程序2:

    image
    • 此時(shí)Runner線程和main線程交替運(yùn)行
* 能使用接口實(shí)現(xiàn)線程就不要用繼承,因?yàn)橛昧私涌谝院筮€可以繼承和實(shí)現(xiàn)其它接口,而如果只繼承會比較死板

4. 創(chuàng)建線程的兩種方式的區(qū)別(掌握)

  • 查看源碼的區(qū)別:
    • a.繼承Thread : 由于子類重寫了Thread類的run(), 當(dāng)調(diào)用start()時(shí), 直接找子類的run()方法
    • b.實(shí)現(xiàn)Runnable : 構(gòu)造函數(shù)中傳入了Runnable的引用, 成員變量記住了它, start()調(diào)用run()方法時(shí)內(nèi)部判斷成員變量Runnable的引用是否為空, 不為空編譯時(shí)看的是Runnable的run(),運(yùn)行時(shí)執(zhí)行的是子類的run()方法
      • Thread類中的run()源碼為:
            public void run() {
                if (target != null) {
                    target.run();
                }
            }

5. 匿名內(nèi)部類實(shí)現(xiàn)線程

  • 繼承Thread類

      new Thread() {                                 //1.繼承Thread類
              public void run(){                      //2.重寫run方法
                  for(int i = 0;i < 1000;i++) {
                      System.out.println("aaaaaa");
                  }
              }
          }.start();                                  //3.開啟線程
    
  • 實(shí)現(xiàn)Runnable接口

      new Thread(new Runnable() {                 //1.將Runnable子類對象傳遞給Thread構(gòu)造方法
          public void run(){                      //2.重寫run方法
              for(int i = 0;i < 1000;i++) {               
                  System.out.println("bb");
              }
          }           
      }).start();                                 //3.開啟線程
    

6. 創(chuàng)建線程的兩種方式的區(qū)別(掌握)

  • 繼承Thread
    • 好處是:可以直接使用Thread類中的方法,代碼簡單
* 弊端是:如果已經(jīng)有了父類,就不能用這種方法
  • 實(shí)現(xiàn)Runnable接口
    • 好處是:即使自己定義的線程類有了父類也沒關(guān)系,因?yàn)橛辛烁割愐部梢詫?shí)現(xiàn)接口,而且接口是可以多實(shí)現(xiàn)的
* 弊端是:不能直接使用Thread中的方法需要先獲取到線程對象后,才能得到Thread的方法,代碼復(fù)雜

7. 線程的第三種創(chuàng)建方式

  • 使用Callable接口_java.util.concurrent

    image
    • Callable接口與Runnable接口的區(qū)別:
      • Runnable沒有返回值一說,而且run()方法并不拋出異常
      • Callable中的call方法具有返回值
      • Callable之所以有返回值,也是因?yàn)閷?shí)現(xiàn)了泛型,而Runnable接口不存在泛型
7.1 FutureTask類的學(xué)習(xí)——java.util.concurrent.FutureTask<V>
image
  • FutureTask的構(gòu)造器
image
  • 此時(shí)可理解為:FutureTask的作用就是接收一個(gè)實(shí)現(xiàn)了Callable接口的實(shí)現(xiàn)類對象

  • 此時(shí)注意到FutureTask實(shí)現(xiàn)了Runnable接口

    • 也就是說可以把FutureTask的實(shí)現(xiàn)類對象傳入到Runnable類型
  • 而Thread類中的構(gòu)造器的參數(shù)為Runnable類型
  • 因此梳理后可知

    ①先實(shí)現(xiàn)Callable接口

      class myThread_3 implements Callable<String>{
          @Override
          public String call() throws Exception {
              return "線程創(chuàng)建成功";
          }
      }
    

    ②將Callable實(shí)現(xiàn)類對象傳給FutureTask構(gòu)造器

      FutureTask<String> ft = new FutureTask<>(new myThread_3());
    
      * 因?yàn)镕utureTask實(shí)現(xiàn)了Runnable接口,因此以下代碼也正確
    
          Runnable runner = new FutureTask<String>(new myThread_3());
          * 接口引用指向?qū)崿F(xiàn)類對象
          * 但是此時(shí)runner只能訪問Runnable中方法,不可以訪問FutureTask中的方法
    

    ③創(chuàng)建線程并啟動

      new Thread(ft).start();
    

    ④使用FutureTask類中方法

      public V get() throws InterruptedException,ExecutionException
    
      通過Thread啟動線程之后 可以通過FutureTask存在get方法可以取得call()方法中的返回值
    
      /*用到Callable有什么用?只是為了返回一個(gè)值?執(zhí)行線程的代碼run用什么代替?*/
      /*回答:此時(shí)線程啟動start()方法調(diào)用的是call()方法,將需要執(zhí)行的代碼放到call()方法中,同時(shí)call()方法的特點(diǎn)在于有返回值*/
    
  • 程序

      public class TestCallable{
          public static void main(String[] args) {
              FutureTask<String> ft = new FutureTask<String>(new myThread_3());
              
              new Thread(ft).start();  //此時(shí)的啟動需要調(diào)用的是call()方法      
              String result = null;
      
              try {
                  result = ft.get();
              } catch (InterruptedException | ExecutionException e) {
                  e.printStackTrace();
              }       
              System.out.println(result);     
              
          }   
      }
      
      class myThread_3 implements Callable<String>{
      
          @Override   
          public String call() throws Exception {     
              System.out.println("此時(shí)start()方法調(diào)用的是call()方法");
              return "線程創(chuàng)建成功";
          }
      }
    
      /*  在JDK1.8中輸出結(jié)果為:
       *  ----------------------------
       *  此時(shí)start()方法調(diào)用的是call()方法
          線程創(chuàng)建成功
          ----------------------------
       * */
    

8. 多線程(獲取名字和設(shè)置名字)(掌握)

  • 獲取名字

    • 通過getName()方法獲取線程對象的名字

        public final String getName();
      
  • 設(shè)置名字

    • 通過構(gòu)造函數(shù)可以傳入String類型的名字

        public Thread(String name)
      
        public Thread(Runnable target,String name)  
      
    • 通過setName(String)方法可以設(shè)置線程對象的名字

        public final void setName(String name);
      
  • 程序?qū)崿F(xiàn)

      new Thread("線程一") {             //設(shè)置線程名字
              public void run() {
                  for(int i = 0;i < 100;i++) {
                      System.out.println(this.getName() + "....aaaa");   //獲取線程名字
                  }
              }
          }.start();
      
      new Thread("線程二") {                 //設(shè)置線程名字
          public void run() {
              for(int i = 0;i < 100;i++) {
                  System.out.println(this.getName() + "....bb");
              }
          }
      }.start();
      
      new Thread() {
          public void run() {
              this.setName("線程3");       //設(shè)置線程名字
              
              for(int i = 0;i < 100;i++) {
                  System.out.println(this.getName() + "....哈哈");
              }
          }
      }.start();
    

9. 多線程(獲取當(dāng)前線程的對象)(掌握)

public static Thread currentThread()

Thread.currentthread();——注意返回值是Thread

//匿名內(nèi)部類實(shí)現(xiàn)當(dāng)前線程對象的獲取
new Thread() {          
    public void run() {
        this.setName("線程A");
        
        for(int i = 0;i < 1000;i++) {
            System.out.println( Thread.currentThread().getName() + "....aaaa");
        }
    }
    
}.start();

new Thread(new Runnable() {
    public void run() {
        for(int i = 0;i < 1000;i++) {
            System.out.println( Thread.currentThread().getName() + "....bb");
        }
    }
},"線程B").start();       

}

10. 多線程(休眠線程)(掌握)

  • public static void sleep(long millis) throws InterruptedException

    • 拋出InterruptionException
        public class TestSleepOfThread {
            public static void main(String[] args) {
                
                Runnable r = ()->{
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    System.out.println("Thread A");
                };
                
                new Thread(r).start();
                
                System.out.println("main Thread");
            }
        }
        /*
         * 在JDK1.8中輸出結(jié)果為:
         * -------------
         * main Thread
           Thread A
           -------------
         * */

11. 多線程(守護(hù)線程)(掌握)

  • setDaemon(), 設(shè)置一個(gè)線程為守護(hù)線程, 該線程不會單獨(dú)執(zhí)行, 當(dāng)其他非守護(hù)線程都執(zhí)行結(jié)束后, 自動退出

  • public final void setDaemon(boolean on)

    • on - if true, marks this thread as a daemon thread

        public class TestSetDaemon {
            public static void main(String[] args) {
                Thread t1 = new Thread("線程A") {
                    public void run() {
                        for(int i = 0;i < 2;i++) {
                            System.out.println(Thread.currentThread().getName() + "....aaaa");
                        }
                    }
                };
                
                Thread t2 = new Thread(new Runnable() {
                    public void run() {
                        for(int i = 0;i < 50;i++) {
                            System.out.println(Thread.currentThread().getName() + "....bb");
                        }
                    }
                },"線程B");
                
                t2.setDaemon(true);          //將t2設(shè)置為守護(hù)線程
                
                t1.start();
                t2.start();
                
            }
        }
        /*
         *  在JDK1.8中輸出結(jié)果為:
         *  ------------------------
         *  線程A....aaaa
            線程B....bb
            線程A....aaaa
            線程B....bb      //存在時(shí)間緩沖問題
            線程B....bb
            線程B....bb
            線程B....bb
            線程B....bb
            線程B....bb
            線程B....bb
         * */
      

12. 多線程(加入線程)(掌握)

  • join(), 當(dāng)前線程暫停, 等待指定的線程執(zhí)行結(jié)束后, 當(dāng)前線程再繼續(xù)

  • join(int), 可以等待指定的毫秒之后繼續(xù)

  • public final void join() throws InterruptedException

      public class TestJoin {
          public static void main(String[] args) {
              
              Thread t1 = new Thread("線程A") {
                  public void run() {
                      for(int i = 0;i < 100;i++) {
                          System.out.println(getName() + "....aaaaaaa");
                      }
                  }
              };
              
              Runnable r = ()->{
                  for(int i = 0;i < 50;i++) {
                      
                      if(i == 2) {
                          try {
                              t1.join();
                              //t1.join(1000); t1插隊(duì)執(zhí)行1秒后,t1和t2線程再搶占CPU交替執(zhí)行
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }               
                      
                      System.out.println(Thread.currentThread().getName() + "....bb");
                  }
              };
              
              t1.start();
              new Thread(r).start();
          }
      }
    

13. 多線程(禮讓線程)(了解)

  • yield讓出cpu

14. 多線程(設(shè)置線程的優(yōu)先級)(了解)

  • setPriority()設(shè)置線程的優(yōu)先級

15. 多線程(同步代碼塊)(掌握)

  • 1.什么情況下需要同步
    • 當(dāng)多線程并發(fā), 有多段代碼同時(shí)執(zhí)行時(shí), 我們希望某一段代碼執(zhí)行的過程中CPU不要切換到其他線程工作. 這時(shí)就需要同步.
    • 如果兩段代碼是同步的, 那么同一時(shí)間只能執(zhí)行一段, 在一段代碼沒執(zhí)行結(jié)束之前, 不會執(zhí)行另外一段代碼.
  • 2.同步代碼塊
    • 使用synchronized關(guān)鍵字加上一個(gè)鎖對象來定義一段代碼, 這就叫同步代碼塊

    • 鎖對象不可以用匿名對象,因?yàn)槟涿麑ο蟛皇峭粋€(gè)對象

    • 多個(gè)同步代碼塊如果使用相同的鎖對象, 那么他們就是同步的

        public class TestTickets_2 {
            public static void main(String[] args) {
                MyThread_6 myt = new MyThread_6();
                
                new Thread(myt,"線程A").start();
                new Thread(myt,"線程B").start();
            }
        }
        
        class MyThread_6 implements Runnable{
        
            private int ticket = 5;
            
            @Override
            public void run() {
                    while(true) {
                        if(this.ticket > 0) {
                            System.out.println(Thread.currentThread().getName() + "開始賣票 = " + ticket--);
                        }
                        else {
                            System.out.println("票已經(jīng)賣完");
                            break;
                        }
                    }   
                }   
        }
      

16. 多線程(同步方法)(掌握)

public class TestSynchronized_2 {
    
    public static void main(String[] args) {
        Printer_2 p = new Printer_2();
        
        Runnable r = ()->{
            for(int i = 0;i < 100;i++) {
                p.print1();
            }
        };
        
        Thread t2 = new Thread() {
            public void run() {
                for(int i = 0;i < 100;i++) {
                    p.print2();
                }
            }
        };
        
        new Thread(r).start();
        t2.start();     
    }
}

class Printer_2{
    public synchronized void print1() {
        System.out.print("早");
        System.out.print("上");
        System.out.print("好");
        System.out.print("啊");
        System.out.print("\r\n");
    }
    
    public void print2() {
        synchronized(this) {
            System.out.print("河");
            System.out.print("正");
            System.out.print("宇");
            System.out.print("好");
            System.out.print("帥");  
            System.out.print("\r\n");
        }       
    }   
}

17. 多線程(線程安全問題)(掌握)

  • 多線程并發(fā)操作同一數(shù)據(jù)時(shí), 就有可能出現(xiàn)線程安全問題

  • 使用同步技術(shù)可以解決這種問題, 把操作數(shù)據(jù)的代碼進(jìn)行同步, 不要多個(gè)線程一起操作

      /*
       *  鐵路售票,一共100張,通過四個(gè)窗口賣完 
       * */
      public class TestSynchronized_3 {
          public static void main(String[] args) {
              new Ticket().start();
              new Ticket().start();
              new Ticket().start();
          }   
      }
      
      class Ticket extends Thread{
          private static int ticket = 100;
          
          public void run() {
              while(true) {
                  //synchronized(this)
                  synchronized(Ticket.class) {
                      if(ticket == 0) {
                          break;
                      }
                      
                      System.out.println(getName() + "這是第" + ticket-- + "號票");
                  }
              }
          }
      }
    

18. 多線程(火車站賣票的例子用實(shí)現(xiàn)Runnable接口)(掌握)

public class TestSynchronized_4 {
    public static void main(String[] args) {
        Ticket_2 t = new Ticket_2();
        
        new Thread(t,"線程A").start();
        new Thread(t,"線程B").start();
        new Thread(t,"線程C").start();
        new Thread(t,"線程D").start();
    }
}

class Ticket_2 implements Runnable{
    private int ticket = 100;  //此時(shí)ticket不需要設(shè)置為共享,因?yàn)榫鶠橥粚ο?    
    @Override
    public void run() {
        while(true) {
            synchronized(this) {
                if(ticket == 0) {
                    break;
                }
                
                System.out.println(Thread.currentThread().getName() + " 這是第" + ticket-- + "號票");
            }
        }
    }
}

19. 多線程(死鎖)(了解)

public class TestDeadLock {
    private static Object o1 = new Object();
    private static Object o2 = new Object();
    
    
    public static void main(String[] args) {
        new Thread("線程A") {
            public void run() {
                while(true) {
                    synchronized(o1) {
                        System.out.println(getName() + "正在使用o1,等待o2");
                        synchronized(o2) {
                            System.out.println(getName()  +"等到o2,執(zhí)行成功");
                        }
                    }
                }               
            }
        }.start();
        
        new Thread("線程B") {
            public void run() {
                while(true) {
                    synchronized(o2) {
                        System.out.println(getName() + "正在使用o2,等待o1");
                        synchronized(o1) {
                            System.out.println(getName() + "等到o1,執(zhí)行成功");
                        }
                    }
                }               
            }
        }.start();
    }
}
/*
 *  在JDK1.8中輸出結(jié)果為:
 *  ----------------------
    線程A正在使用o1,等待o2
    線程A等到o2,執(zhí)行成功
    線程A正在使用o1,等待o2
    線程B正在使用o2,等待o1
    -------------------------
 * */
  • 因此:synchronized不要嵌套使用,容易出錯

20. 多線程和隊(duì)列實(shí)現(xiàn)買賣票

Queue接口
public interface Queue {
    
    public void append(Object obj)throws Exception;
    
    public Object delete()throws Exception;

    public Object getFront()throws Exception;   
    
    public boolean isEmpty();
}
Class MyQueue
public class MyQueue implements Queue{
        
        //1 設(shè)置隊(duì)列的默認(rèn)長度
        
        static final int DEFAULT_SIZE=10;  //默認(rèn)長度為10
        
        //2 設(shè)置隊(duì)頭
        
        int front; 
        
        //3 設(shè)置隊(duì)尾
        
        int rear;
        
        //4 定義統(tǒng)計(jì)元素的變量
        
        int count;
        
        //5 隊(duì)的最大長度
        
        int maxSize;
        
        Object[] queue;  //設(shè)置隊(duì)列
        
        //空構(gòu)造
        public MyQueue() {
            
            this.init(DEFAULT_SIZE);  //用戶給定長度 默認(rèn)長度為10
        }
        
        
        //有參數(shù)的構(gòu)造
        public MyQueue(int size) {
            
            this.init(size);  //開辟用戶給定的長度
        }
        
        /**
         * 初始化方法
         * @param size
         */
        public void init(int size) {
            
            //初始化屬性
            this.maxSize=size;  //外部傳進(jìn)來的size
            
            //空隊(duì)列
            front=rear=0;
            
            count=0;
            
            queue=new Object[size];
        }
        
        @Override
        public void append(Object obj) throws Exception {
            // TODO Auto-generated method stub
            //首先隊(duì)列是否已滿
            if(count>0&&front==rear) {  //判斷隊(duì)列是否已滿
                
                throw new Exception("隊(duì)列已滿");
            }
            
            this.queue[rear]=obj;
            rear=(rear+1)%maxSize;
            count++;
        }

        @Override
        public Object delete() throws Exception {
            // TODO Auto-generated method stub
            if(this.isEmpty()) {
                
                throw new Exception("隊(duì)列為空隊(duì)");
            }
            
            Object obj=this.queue[front];
            front=(front+1)%maxSize;
            count--;
            
            return obj;
            
        }

        @Override
        public Object getFront() throws Exception {
            // TODO Auto-generated method stub
            if(!this.isEmpty()) {
                
                return this.queue[front];
            }
            return null;
        }

        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            return this.count==0;
        }
    }
Class WindowQueue
public class WindowQueue { //賣票的窗口

    //定義賣票隊(duì)列
    
    int maxSize=10;
    
    MyQueue queue=new MyQueue(maxSize);
    
    int num=0; //最多賣100張票
    
    boolean flag=true ; //判斷是否繼續(xù)賣票
    
    
    //排隊(duì)買票
    public synchronized void producer()throws Exception{
        
        if(this.queue.count<maxSize) {
            
            this.queue.append(num++); //等待買票的數(shù)量++
            System.out.println("第"+num+"個(gè)客戶排隊(duì)買票");
            this.notifyAll(); //喚醒等待的線程
        }else {
            
            System.out.println("隊(duì)列已滿 請等待");
            this.wait(); 
        }
    }
    
    
    //賣票
    public synchronized void consumer()throws Exception{
        
        if(this.queue.count>0) {
            Object obj=this.queue.delete();  //出隊(duì)
            int temp=Integer.parseInt(obj.toString());
            System.out.println("第"+(temp+1)+"個(gè)客戶買到票離開隊(duì)列");
            
            //如果當(dāng)前的隊(duì)列為空 并且賣出票數(shù)大于100
            if(this.queue.isEmpty()&&this.num>=100) {
                
                this.flag=false;
            }
            this.notifyAll(); //喚醒等待的線程
        }else {
            
            System.out.println("隊(duì)列已空 請等待");
            this.wait();
        }
    }
}
Class Producer
public class Producer implements Runnable{

    WindowQueue queue;
    
    public Producer(WindowQueue queue) {
        
        this.queue=queue;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(queue.num<100) {  //必須小于100張票 才可以買票
        try {
            Thread.sleep(1000);
            queue.producer();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    }

}
Class Consumer
public class Consumer implements Runnable{
    
    WindowQueue queue;
    
    public Consumer(WindowQueue queue) {
        
        this.queue=queue;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(queue.flag) {  //如果隊(duì)列為空 并且票數(shù)大于100 就不會賣票了
            
            try {
                Thread.sleep(1000);
                queue.consumer();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}
Class QueueTest
public class QueueTest {        
    public static void main(String[] args) throws Exception {       
        WindowQueue queue=new WindowQueue();
        Producer p=new Producer(queue);
        
        Consumer con=new Consumer(queue);
        
        //以上的代碼一定要注意 傳入的是同一個(gè)對象
        
        Thread t1=new Thread(p);
        
        Thread t2=new Thread(con);
        
        
        t1.start();
        
        t2.start();
    }
}

Lambda表達(dá)式

  • Lambda表達(dá)式的形式

    參數(shù),箭頭(→)以及一個(gè)表示

  • Lambda適用于接口中一個(gè)抽象方法時(shí)候使用

  • 舉例1——函數(shù)式接口使用

      Runnable runner = ()->{
          StringBuffer s = new StringBuffer();
          
          for(int i= 0;i < 10;i++)
              System.out.println(s.append("haha"));
      };
    
  • 舉例2——只有一個(gè)抽象方法的接口的實(shí)現(xiàn)類的使用

      Thread t1 = new Thread(()->{
          StringBuffer s = new StringBuffer();
          
          for(int i= 0;i < 10;i++)
              System.out.println(s.append("haha"));
      });
    
  • 區(qū)別于匿名內(nèi)部類——需要寫出方法聲明

      new Thread(new Runnable() {
          public void run() {
              StringBuffer s = new StringBuffer();
              
              for(int i= 0;i < 10;i++)
                  System.out.println(s.append("haha"));
          }           
      }).start(); 
    
    
    
      Thread t1 = new Thread() {
          public void run() {
              StringBuffer s = new StringBuffer();
              
              for(int i= 0;i < 10;i++)
                  System.out.println(s.append("haha"));
          }
      };
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,641評論 18 399
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,107評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,594評論 1 15
  • 老二摸著黑下了床,為了使自己的腳步聲音聽起來很輕,他并沒有穿鞋,哪怕是拉開插銷的動作看起來都細(xì)微無比,門輕輕的打開...
    秦約取閱讀 288評論 0 0
  • 編輯區(qū)最大化的時(shí)候控制臺有新的輸出的時(shí)候會彈窗很煩人, command+,跳出設(shè)置菜單然后到Run/debug--...
    RobertCrazying閱讀 263評論 0 0

友情鏈接更多精彩內(nèi)容