多是東半球最好的多線程講義!

JAVA多線程java

多線程的基本概念

線程指進程中的一個執行場景,也就是執行流程,那麼進程和線程有什麼區別呢?算法

  • 每一個進程是一個應用程序,都有獨立的內存空間編程

  • 同一個進程中的線程共享其進程中的內存和資源(共享的內存是堆內存和方法區內存,棧內存不共享,每一個線程有本身的。)windows

什麼是進程?

一個進程對應一個應用程序。例如:在 windows 操做系統啓動 Word 就表示啓動了一個
進程。在 java 的開發環境下啓動 JVM,就表示啓動了一個進程。現代的計算機都是支持多
進程的,在同一個操做系統中,能夠同時啓動多個進程。安全

多進程有什麼做用?

單進程計算機只能作一件事情。
玩電腦,一邊玩遊戲(遊戲進程)一邊聽音樂(音樂進程)。
對於單核計算機來說,在同一個時間點上,遊戲進程和音樂進程是同時在運行嗎?不是。
由於計算機的 CPU 只能在某個時間點上作一件事。因爲計算機將在「遊戲進程」和「音樂
進程」之間頻繁的切換執行,切換速度極高,人類感受遊戲和音樂在同時進行。
多進程的做用不是提升執行速度,而是提升 CPU 的使用率。
進程和進程之間的內存是獨立的。多線程

什麼是線程?

線程是一個進程中的執行場景。一個進程能夠啓動多個線程。併發

多線程有什麼做用?

多線程不是爲了提升執行速度,而是提升應用程序的使用率。
線程和線程共享「堆內存和方法區內存」,棧內存是獨立的,一個線程一個棧。
能夠給現實世界中的人類一種錯覺:感受多個線程在同時併發執行。異步

java 程序的運行原理?

java 命令會啓動 java 虛擬機,啓動 JVM,等於啓動了一個應用程序,表示啓動了一個進程。該進程會自動啓動一個「主線程」,而後主線程去調用某個類的 main 方法。因此 main方法運行在主線程中。在此以前的全部程序都是單線程的。ide

線程生命週期

線程是一個進程中的執行場景,一個進程能夠啓動多個線程 異步編程

1 (2).png

新建:採用 new 語句建立完成
就緒:執行 start 後
運行:佔用 CPU 時間
阻塞:執行了 wait 語句、執行了 sleep 語句和等待某個對象鎖,等待輸入的場合
終止:退出 run()方法

多線程不是爲了提升執行速度,而是提升應用程序的使用率.

線程和線程共享」堆內存和方法區內存」.棧內存是獨立的,一個線程一個棧.

能夠給現實世界中的人類一種錯覺 : 感受多線程在同時併發執行.

不少人都對其中的一些概念不夠明確,如同步、併發等等,讓咱們先創建一個數據字典,以避免產生誤會。

  • 多線程:指的是這個程序(一個進程)運行時產生了不止一個線程

  • 並行與併發:

·          

    • 並行:多個cpu實例或者多臺機器同時執行一段處理邏輯,是真正的同時。

·          

    • 併發:經過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操做層面不是真正的同時。併發每每在場景中有公用的資源,那麼針對這個公用的資源每每產生瓶頸,咱們會用TPS或者QPS來反應這個系統的處理能力。

線程安全:常常用來描繪一段代碼。指在併發的狀況之下,該代碼通過多線程使用,線程的調度順序不影響任何結果。這個時候使用多線程,咱們只須要關注系統的內存,cpu是否是夠用便可。反過來,線程不安全就意味着線程的調度順序會影響最終結果,如不加事務的轉帳代碼:

     void transferMoney(User from, User to, float amount) {
 
      to.setMoney(to.getBalance() + amount);
 
      from.setMoney(from.getBalance() - amount);
     }

同步:Java中的同步指的是經過人爲的控制和調度,保證共享資源的多線程訪問成爲線程安全,來保證結果的準確。如上面的代碼簡單加入@synchronized關鍵字。在保證結果準確的同時,提升性能,纔是優秀的程序。線程安全的優先級高於性能。

Java命令會啓動Java虛擬機,啓動JVM,等於啓動了一個應用程序,表示啓動了一個進程,該進程會自動啓動一個」主線程」,

而後主線程去調用某個類的main()方法,因此main()方法運行在主線程中.

2.png

http://upload-images.jianshu.io/upload_images/1689841-383f7101e6588094.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240&_=5479442

線程的調度與控制

線程的調度模型分爲: 分時調度模型搶佔式調度模型,Java使用搶佔式調度模型
一般咱們的計算機只有一個 CPU,CPU 在某一個時刻只能執行一條指令,線程只有獲得 CPU時間片,也就是使用權,才能夠執行指令。在單 CPU 的機器上線程不是並行運行的,只有在多個 CPU 上線程才能夠並行運行。Java 虛擬機要負責線程的調度,取得 CPU 的使用權,目前有兩種調度模型:分時調度模型和搶佔式調度模型,Java 使用搶佔式調度模型。分時調度模型:全部線程輪流使用 CPU 的使用權,平均分配每一個線程佔用 CPU 的時間片搶佔式調度模型:優先讓優先級高的線程使用 CPU,若是線程的優先級相同,那麼會隨機選擇一個,優先級高的線程獲取的 CPU 時間片相對多一些。

l  分時調度模型: 全部線程輪流使用CPU的使用權,平均分配每一個線程佔用CPU的時間片

l  搶佔式調度模型: 優先讓優先級高的線程使用CPU,若是線程的優先級相同,那麼會隨機選擇一個,優先級高的線程獲取的CPU時間片相對多一些.

 

public class ThreadTest {

 

   public static void main(String[] args) {

      ThreadTest1();

      // ThreadTest2();

      // ThreadTest3();

      // ThreadTest4();

      // ThreadTest5();

   }

 

   /**

    * 三個方法: 獲取當前線程對象:Thread.currentThread(); 給線程起名: t1.setName("t1"); 獲取線程的名字:

    * t.getName();

    */

   private static void ThreadTest1() {

      Thread t = Thread.currentThread();// t保存的內存地址指向的線程爲"主線程"

      System.out.println(t.getId());

      Thread t1 = new Thread(new Processor1());

      // 給線程起名

      t1.setName("t1");

      t1.start();

      Thread t2 = new Thread(new Processor1());

      t2.setName("t2");

      t2.start();

   }

 

   /**

    * 線程優先級高的獲取的CPU時間片相對多一些 優先級: 1-10 最低: 1 最高: 10 默認: 5

    */

   private static void ThreadTest2() {

      Thread t1 = new Processor2();

      Thread t2 = new Processor2();

      t1.setName("t1");

      t2.setName("t2");

 

      System.out.println(t1.getPriority());

      System.out.println(t2.getPriority());

      t1.setPriority(1);

      t2.setPriority(10);

 

      t1.start();

      t2.start();

   }

 

   /**

    * 1.Thread.sleep(毫秒); 2.sleep方法是一個靜態方法 3.該方法的做用: 阻塞當前線程,騰出CPU,讓給其它線程

    */

   private static void ThreadTest3() {

      Thread t = new Thread(new Processor3());

      t.start();

      for (int i = 0; i < 11; i++) {

         System.out.println(Thread.currentThread().getName() + "========>"

                + i);

         try {

            t.sleep(5000);// 等同於Thread.sleep(5000);阻塞的仍是當前線程,t線程無關.

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

   }

 

   /**

    * 某線程正在休眠,如何打斷它的休眠 如下方式依靠的是異常處理機制

    */

   private static void ThreadTest4() {

      try {

         Thread t = new Thread(new Processor4());

         t.start();

         Thread.sleep(5000);// 5s

         t.interrupt();// 打斷Thread的睡眠

      } catch (InterruptedException e) {

         e.printStackTrace();

      }

   }

 

   /**

    * 如何正確的更好的終止一個正在執行的線程 需求:線程啓動5s以後終止.

    */

   private static void ThreadTest5() {

      Processor5 p = new Processor5();

      Thread t = new Thread(p);

      t.start();

      // 5s以後終止

      try {

         Thread.sleep(5000);

         p.isRun = false;

      } catch (InterruptedException e) {

         // TODO Auto-generated catch block

         e.printStackTrace();

      }

   }

}

 

class Processor1 implements Runnable {

 

   @Override

   public void run() {

      Thread t = Thread.currentThread();// t保存的內存地址指向的線程爲"t1線程對象"

      System.out.println(t.getName());

      System.out.println(t.getId());

 

   }

}

 

class Processor2 extends Thread {

 

   @Override

   public void run() {

      for (int i = 0; i < 50; i++) {

         System.out.println(Thread.currentThread().getName()

                + "----------->" + i);

      }

 

   }

}

 

class Processor3 implements Runnable {

 

   /**

    * Thread中的run方法不能拋出異常,因此重寫runn方法以後,run方法的聲明位置上不能使用throws

    * 因此run方法中的異常只能try...catch...

    */

   @Override

   public void run() {

      for (int i = 0; i < 11; i++) {

         System.out.println(Thread.currentThread().getName() + "========>"

                + i);

         try {

            Thread.sleep(1000);

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

   }

 

}

 

class Processor4 implements Runnable {

 

   @Override

   public void run() {

      try {

         Thread.sleep(1000000000);

         System.out.println("可否執行這裏");

      } catch (InterruptedException e) {

         e.printStackTrace();

      }

      for (int i = 0; i < 11; i++) {

         System.out.println(Thread.currentThread().getName() + "========>"

                + i);

      }

   }

}

 

class Processor5 implements Runnable {

 

   boolean isRun = true;

 

   @Override

   public void run() {

      for (int i = 0; i < 11; i++) {

         if (isRun) {

            try {

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(Thread.currentThread().getName()

                   + "========>" + i);

         }

      }

   }

}

線程優先級

線 程 優 先 級 主 要 分 三 種 : MAX_PRIORITY( 最 高  );MIN_PRIORITY ( 最 低 級 )NORM_PRIORITY(標準)默認

//設置線程的優先級,線程啓動後不能再次設置優先級
//必須在啓動前設置優先級
//設置最高優先級
t1.setPriority(Thread.MAX_PRIORITY);


sleep

public class SleepTest {

    public static void main(String[] args) {

       System.out.println("Wait");

       // 讓主線程等待5秒再執行

       Wait.bySec(5);

       // 提示恢復執行

       System.out.println("start");

    }

}

class Wait {

    public static void bySec(long s) {

       // sleep s1

       for (int i = 0; i < s; i++) {

           System.out.println(i + 1 + "");

           try {

              // sleep1

              Thread.sleep(1000);

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

       }

    }

}

中止一個線程

l  若是咱們的線程正在睡眠,能夠採用 interrupt 進行中斷

l  一般定義一個標記,來判斷標記的狀態中止線程的執行

yield

它與 sleep()相似,只是不能由用戶指定暫停多長時間,而且 yield()方法只能讓同優先級的線程有執行的機會,採用 yieid 能夠將 CPU 的使用權讓給同一個優先級的線程


public class YieldTest {

    public static void main(String[] args) {

       FirstThread mt = new FirstThread();

        SecThread mnt = new SecThread();

        mt.start();

        mnt.start();

      }

}

class FirstThread extends Thread{

   public void run(){

       for(int i=0;i<5;i++){

           System.out.println("第一個線程的第 "+(i+1)+"次運行");

           Thread.yield();  //暫停線程

       }

    }

}

class SecThread extends Thread{

    public void run(){

       for(int i=0;i<5;i++){

           System.out.println("第二個線程的第 "+(i+1)+"次運行");

           Thread.yield();

       }

   }

}


join

當前線程能夠調用另外一個線程的 join 方法,調用後當前線程會被阻塞再也不執行,直到被調用的線程執行完畢,當前線程纔會執行


public class JoinTest extends Thread {

    public JoinTest(String name) {

       super(name);

    }

    public void run() {

       for (int i = 0; i < 5; i++)

           System.out.println(getName() + "" + i);

    }

    public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           if (i == 5) {

              JoinTest tempjt = new JoinTest("半路加入的線程");

              try {

                  tempjt.start();

                  tempjt.join();

              } catch (InterruptedException e) {

                  e.printStackTrace();

              }

           }

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

       }

    }

}

 


synchronized

線程同步,指某一個時刻,指容許一個線程來訪問共享資源,線程同步實際上是對對象加鎖,若是對象中的方法都是同步方法,那麼某一時刻只能執行一個方法,採用線程同步解決以上的問題,咱們只要保證線程一操做 s 時,線程 2 不容許操做便可,只有線程一使用完成 s 後,再讓線程二來使用 s 變量

·         異步編程模型 : t1線程執行t1的,t2線程執行t2的,兩個線程之間誰也不等誰.

·         同步編程模型 : t1線程和t2線程執行,t2線程必須等t1線程執行結束以後,t2線程才能執行,這是同步編程模型.

·        

·         何時要用同步呢?爲何要引入線程同步呢?

·         1.爲了數據的安全,儘管應用程序的使用率下降,可是爲了保證數據是安全的,必須加入線程同步機制.

·         線程同步機制使程序變成了(等同)單線程.

·         2.什麼條件下要使用線程同步?

·         第一: 必須是多線程環境

·         第二: 多線程環境共享同一個數據.

·         第三: 共享的數據涉及到修改操做.

 


   // synchronized 是對對象加鎖

   // 採用 synchronized 同步最好只同步有線程安全的代碼

   // 能夠優先考慮使用 synchronized 同步塊

   // 由於同步的代碼越多,執行的時間就會越長,其餘線程等待的時間就會越長

   // 影響效率

public class TestWithdrawal {

    public static void main(String[] args) {

       // 建立兩個線程

       TestAccount r = new TestAccount();

       Thread one = new Thread(r);

       Thread two = new Thread(r);

       one.setName("張三");

       two.setName("張三的妻子");

       // 啓動線程

       one.start();

       two.start();

    }

}

 

class Account {

    private int balance = 500; // 餘額

 

    public int getBalance() {

       return balance;

    }

 

    // 取款

    public void withdraw(int amount) {

       balance = balance - amount;

    }

}

 

class TestAccount implements Runnable {

    // 全部用TestAccount對象建立的線程共享同一個賬戶對象

    private Account acct = new Account();

 

    public void run() {

       for (int i = 0; i < 5; i++) {

           makeWithdrawal(100);// 取款

           if (acct.getBalance() < 0) {

              System.out.println("帳戶透支了!");

           }

       }

    }

 

    private void makeWithdrawal(int amt) {

       synchronized (acct) {

           if (acct.getBalance() >= amt) {

              System.out.println(Thread.currentThread().getName() + " 準備取款");

              try {

                  Thread.sleep(500);// 0.5秒後實現取款

              } catch (InterruptedException ex) {

              }

              // 若是餘額足夠,則取款

              acct.withdraw(amt);

              System.out.println(Thread.currentThread().getName() + " 完成取款,餘額:"+acct.getBalance());

           } else {

              // 餘額不足給出提示

              System.out.println("餘額不足以支付 "

                     + Thread.currentThread().getName() + " 的取款,餘額爲 "

                     + acct.getBalance());

           }

       }

    }

}

 


死鎖

public class DeadLock {

 

    public static void main(String[] args) {

       Object o1 = new Object();

       Object o2 = new Object();

       Thread t1 = new Thread(new T1(o1, o2));

       Thread t2 = new Thread(new T2(o1, o2));

       t1.start();

       t2.start();

    }

}

 

class T1 implements Runnable {

 

    Object o1;

    Object o2;

 

    T1(Object o1, Object o2) {

       this.o1 = o1;

       this.o2 = o2;

    }

 

    @Override

    public void run() {

       synchronized (o1) {

           try {

              Thread.sleep(1000);

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

           synchronized (o2) {

 

           }

       }

    }

}

 

class T2 implements Runnable {

 

    Object o1;

    Object o2;

 

    T2(Object o1, Object o2) {

       this.o1 = o1;

       this.o2 = o2;

    }

 

    @Override

    public void run() {

       synchronized (o2) {

           try {

              Thread.sleep(1000);

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

           synchronized (o1) {

 

           }

       }

    }

}


守護線程

從線程分類上能夠分爲:用戶線程(以上講的都是用戶線程),另外一個是守護線程。守護線程是這樣的,全部的用戶線程結束生命週期,守護線程纔會結束生命週期,只要有一個用戶線程存在,那麼守護線程就不會結束,例如 java 中著名的垃圾回收器就是一個守護線程,只有應用程序中全部的線程結束,它纔會結束。

·         其它全部的用戶線程結束,則守護線程退出!

·         守護線程通常都是無限執行的.

public class DaemonThread {

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

      Thread t1 = new Thread(new Runnable2());

      t1.setName("t1");

      // t1這個用戶線程修改爲守護線程.在線程沒有啓動時能夠修改如下參數

      t1.setDaemon(true);

      t1.start();

      // 主線程

      for (int i = 0; i < 10; i++) {

         System.out.println(Thread.currentThread().getName() + "----->" + i);

         Thread.sleep(1000);

      }

   }

}

 

class Runnable2 implements Runnable {

 

   @Override

   public void run() {

      int i = 0;

      while (true) {

         i++;

         System.out.println(Thread.currentThread().getName() + "-------->"

                + i);

         try {

            Thread.sleep(500);

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

   }

}
 
設置爲守護線程後,當主線程結束後,守護線程並無把全部的數據輸出完就結束了,也便是說守護線程是爲用戶線程服務的,當用戶線程所有結束,守護線程會自動結束
 


Timer.schedule()

/**

 * 關於定時器的應用 做用: 每隔一段固定的時間執行一段代碼

 */

public class TimerTest {

 

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

      // 1.建立定時器

      Timer t = new Timer();

      // 2.指定定時任務

      t.schedule(new LogTimerTask(), new SimpleDateFormat(

            "yyyy-MM-dd HH:mm:ss SSS").parse("2017-06-29 14:24:00 000"),

            10 * 1000);

   }

}

 

// 指定任務

class LogTimerTask extends TimerTask {

 

   @Override

   public void run() {

      System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS")

            .format(new Date()));

   }

}

我是melon,一個10年編程老司機。Q我3474203856。 給melon留言或者說明是看到文章過來的。全部相關技術問題均可以一塊兒尋找到答案。

相關文章
相關標籤/搜索