程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> JAVAThread 多線程學習

JAVAThread 多線程學習

編輯:JAVA綜合教程

JAVAThread 多線程學習


開始第二遍學習java了,發現有好多的知識點在之前學習的時候是不了解的。在java多線程的板塊中,學到了除了繼承Thread 實現runnable接口以外 還學到了第三種的基於線程池的實現callable接口的線程方式。感覺java真實博大精深。對java線程的筆記總結:

java線程

java程序由一條線程執行完畢 稱為單線程程序

java程序由多條程序執行完畢 稱為多線程程序

1:多線程
(1)多線程:一個應用程序有多條執行路徑 進程:正在執行的應用程序 線程:進程的執行單元,執行路徑 單線程:一個應用程序只有一條執行路徑 多線程:一個應用程序有多條執行路徑

    多進程的意義?   
        提高CPU的使用率
    多線程的意義?
        提高應用程序的使用率
(2)Java程序的運行原理及JVM的啟動是多線程的嗎?
    A:Java命令去啟動JVM,JVM會啟動一個進程,該進程會啟動一個主線程。
    B:JVM的啟動是多線程的,因為它最低有兩個線程啟動了,主線程和垃圾回收線程。

(3)多線程的實現方案

A:繼承Thread類
B:實現Runnable接口
* 兩種方式的比較   

\

(4)線程的調度和優先級問題

A:線程的調度
  • a:分時調度
  • b:搶占式調度 (Java采用的是該調度方式)
  • B:獲取和設置線程優先級
        a:默認是5
        b:范圍是1-10
    

    (5)線程的控制(常見方法)

    A:休眠線程

    API方法:

    線程睡眠毫秒數

    • public static void sleep(long millis)

      B:加入線程

      API方法

      join:等待線程終止,等待線程執行完畢後其它的線程才可以運行

      • public final void join();

        C:礼讓線程

        API方法

        一定程度上讓多個線程的執行和諧,不靠譜

        • public static void yield()

          D:後台線程

          API方法
          • public final void setDaemon(boolean on)
            當正在運行的線程都是守護線程時,java虛擬機退出,該方法必須在線程啟動之前調用
            標記為守護線程後,線程會依附於某個線程,不會獨立的run

            E:終止線程(掌握)

            API方法
            • public final void stop() 讓線程停止,已過時

            • public void interrupt() 終止線程,並且拋出InterruptedException異常,並會執行後續的代碼

              線程的生命周期(參照 線程生命周期圖解.bmp)

              \

              A:新建

              創建線程對象的過程<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPGg0PkI6vs3Q9zwvaDQ+CjxwPgrT0Na00NC1xMz1vP66zdfKJiMyNjY4NDujrMO709DWtNDQyKg8L3A+CjxoND5jOtTL0NA8L2g0Pgo8cD4K09DUy9DQtcTXyiYjMjY2ODQ7o6zT0Na00NDIqDwvcD4KPGg0PkQ61+jI+zwvaDQ+CjxwPgrDu9PQ1rTQ0NfKJiMyNjY4NDujrMO709DWtNDQyKg8L3A+CjxoND5FOsvAzfY8L2g0Pgo8cD4Kz9+zzLbUz/Ox5LPJwKy7+KOstci0/bG7u9jK1TwvcD4KPHByZSBjbGFzcz0="brush:java;">(7)電影院賣票程序的實現 A:繼承Thread類 B:實現Runnable接口 (8)電影院賣票程序出問題 A:為了更符合真實的場景,加入了休眠100毫秒。 B:賣票問題 a:同票多次 b:負數票 (9)多線程安全問題的原因(也是我們以後判斷一個程序是否有線程安全問題的依據) A:是否有多線程環境 B:是否有共享數據 C:是否有多條語句操作共享數據

              (10)同步解決線程安全問題

              A:同步代碼塊

              synchronized(對象) {
              需要被同步的代碼;
              }

              這裡的鎖對象可以是任意對象。

              B:同步方法

              把同步加在方法上。

              這裡的鎖對象是this

              C:靜態同步方法

              把同步加在方法上。

              這裡的鎖對象是當前類的字節碼文件對象(反射再講字節碼文件對象)

              (11)回顧以前的線程安全的類
              • A:StringBuffer
              • B:Vector
              • C:Hashtable
              • D:如何把一個線程不安全的集合類變成一個線程安全的集合類用Collections工具類的方法即可。

              相關知識點

              (1)JDK5以後的針對線程的鎖定操作和釋放操作

              Lock鎖
                  // 定義鎖對象
                  private Lock lock = new ReentrantLock();
              
                  @Override
                  public void run() {
                      while (true) {
                          try {
                              // 加鎖
                              lock.lock();
                              if (tickets > 0) {
                                  try {
                                      Thread.sleep(100);
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                                  System.out.println(Thread.currentThread().getName()
                                          + "正在出售第" + (tickets--) + "張票");
                              }
                          } finally {
                              // 釋放鎖
                              lock.unlock();
                          }
                      }
                  }
              
              (2)死鎖問題的描述和代碼體現
              • 是指兩個或者兩個以上的線程在執行的過程中,因爭奪資源產一種互相等待現象
              • 同步代碼塊的嵌套案例
                  @Override
              public void run() {
                  // 死鎖代碼
                  if (flag) {
                      // 同步嵌套
                      synchronized (MyLock.objA) {
                          System.out.println("if obja");
                          synchronized (MyLock.objB) {
                              System.out.println("if objb");
                          }
                      }
                  } else {
                      synchronized (MyLock.objB) {
                          System.out.println("else objb");
                          synchronized (MyLock.objA) {
                              System.out.println("else obja");
              
                          }
                      }
                  }
              }
              
              (3)生產者和消費者多線程體現(線程間通信問題)
                  以學生作為資源來實現的
              
                  資源類:Student
                  設置數據類:SetThread(生產者)
                  獲取數據類:GetThread(消費者)
                  測試類:StudentDemo
              
                  代碼:
                      A:最基本的版本,只有一個數據。
                      B:改進版本,給出了不同的數據,並加入了同步機制
                      C:等待喚醒機制改進該程序,讓數據能夠實現依次的出現
                          wait() 線程等待後立即釋放所持有的鎖,被喚醒後在等待的位置繼續執行
                          notify() 喚醒並不代表立馬可以執行 線程會轉為就緒狀態 等待下一次執行
                          notifyAll() (多生產多消費)   
              
              • 為什麼定義在Object中?
                • 這些方法的調用通過鎖對象調用,而我們使用的鎖可能是任意鎖對象。所以,這些方法必須定義在Object類中 =* 等待喚醒機制的代碼優化。把數據及操作都寫在了資源類中
                  (4)線程組
                  • Java中使用ThreadGroup來表示線程組,它可以對一批線程進行分類管理,Java允許程序直接對線程組進行控制。 默認情況下,所有的線程都屬於主線程組(main組)。
                    返回該線程所屬的線程組
                  • public final ThreadGroup getThreadGroup()
                    我們也可以給線程設置分組
                  • Thread(ThreadGroupgroup, Runnabletarget, Stringname)
                    新建線程組代碼:

                        // ThreadGroup(String name)
                        ThreadGroup tg = new ThreadGroup("這是一個新的組");
                    
                        MyRunnable my = new MyRunnable();
                        // Thread(ThreadGroup group, Runnable target, String name)
                        Thread t1 = new Thread(tg, my, "林青霞");
                        Thread t2 = new Thread(tg, my, "劉意");
                    
                        System.out.println(t1.getThreadGroup().getName());
                        System.out.println(t2.getThreadGroup().getName());
                    
                        //通過組名稱設置後台線程,表示該組的線程都是後台線程
                        tg.setDaemon(true);
                    
                    (5)線程池

                    程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統進行交互。而使用線程池可以很好的提高性能,尤其是當程序中要創建大量生存期很短的線程時,更應該考慮使用線程池。

                    • 線程池裡的每一個線程代碼結束後,並不會死亡,而是再次回到線程池中成為空閒狀態,等待下一個對象來使用。
                    • 在JDK5之前,我們必須手動實現自己的線程池,從JDK5開始,Java內置支持線程池
                    • JDK5新增了一個Executors工廠類來產生線程池,有如下幾個方法

                      public static ExecutorService newCachedThreadPool()

                      創建一個具有緩存功能的線程池
                      緩存:百度浏覽過的信息再次訪問   
                      

                      public static ExecutorService newFixedThreadPool(int nThreads)

                      創建一個可重用的,具有固定線程數的線程池
                      

                      public static ExecutorService newSingleThreadExecutor()

                      創建一個只有單線程的線程池,相當於上個方法的參數是1   
                      

                      protected void shutdown()
                      順序關閉線程池中的線程 這些方法的返回值是ExecutorService對象,該對象表示一個線程池,可以執行Runnable對象或者Callable對象代表的線程。它提供了如下方法
                      Future submit(Runnable task)
                      Futuresubmit(Callabletask)

                      (6)多線程實現的第三種方案

                      實現Callable接口 步驟和剛才演示線程池執行Runnable對象的差不多。 但是還可以更好玩一些,求和案例演示 好處: 可以有返回值 可以拋出異常 弊端: 代碼比較復雜,所以一般不用

                      匿名內部類方式使用多線程

                      new Thread(){代碼…}.start(); New Thread(new Runnable(){代碼…}).start();

                      多線程的應用

                      定時器的使用
                      描述:
                      • 定時器是一個應用十分廣泛的線程工具,可用於調度多個定時任務以後台線程的方式執行。在Java中,可以通過Timer和TimerTask類來實現定義調度的功能

                      • Timer 一種工具,線程用其安排以後在後台線程中執行的任務。可安排任務執行一次,或者定期重復執行。

                        public Timer()
                        public void schedule(TimerTasktask, longdelay)
                        public void schedule(TimerTask task,long delay,long period)
                        * TimerTask 任務類用於為Timer指定任務 public abstract void run()
                        public boolean cancel()
                        * 開發中
                        Quartz是一個完全由java編寫的開源調度框架。

                        線程的生命周期轉換圖:


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved