溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何學習Java多線程

發布時間:2021-09-30 17:05:29 來源:億速云 閱讀:169 作者:iii 欄目:開發技術

本篇內容主要講解“如何學習Java多線程”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何學習Java多線程”吧!

目錄
  • 多任務、多線程

  • 程序、進程、線程

  • 學著看jdk文檔

  • 線程的創建

    • 1.繼承Thread類

    • 2.實現Runable接口

    • 理解并發的場景

    • 龜兔賽跑場景

    • 實現callable接口

  • 理解函數式接口

    • 理解線程的狀態

      • 線程停止

      • 線程休眠sleep

        • 1.網路延遲

        • 2.倒計時等

      • 線程禮讓yield

        • 線程強制執行

        • 觀察線程狀態

          • 線程的優先級

            • 守護線程

              • 線程同步機制

                • 1.synchronized 同步方法

                  • 2.同步塊synchronized(Obj){}

                  • lock

                    • synchronized與lock

                      多任務、多線程

                      在多任務場景下,兩件事看上去同時在做,但實際上,你的大腦在同一時間只做一件事,間隔時間可能很少,但這似乎讓你感覺這兩件事是同時在做

                      考慮阻塞問題,引入多線程的場景,多線程并發場景

                      如何學習Java多線程

                      程序、進程、線程

                      程序=指令+數據(靜態的)
                      在操作系統中運行的程序就是進程,一個進程可以有多個線程
                      比如,看視頻時聽聲音,看圖像,看彈幕等

                      學著看jdk文檔

                      比如你要看Thread
                      你可以搜索,然后閱讀

                      如何學習Java多線程

                      往下翻你會看到:

                      如何學習Java多線程

                      如何學習Java多線程

                      如何學習Java多線程

                      線程的創建

                      1.繼承Thread類

                      //創建線程方式一:繼承Thread類,重寫run方法,調用start()方法開啟線程
                      public class TestThread1  extends Thread{
                      
                          @Override
                          public void run() {
                              //run()方法線程體
                              IntStream.range(0,20).forEach(i->{
                                  System.out.println("我在看代碼"+i);
                              });
                          }
                      
                          public static void main(String[] args) {
                              //創建一個線程對象
                              TestThread1 testThread1=new TestThread1();
                              //調用start()方法,啟動線程,不一定立即執行,由cpu調度執行
                              testThread1.start();
                      
                              //主方法 main方法
                              IntStream.range(0,20).forEach(i->{
                                  System.out.println("我在學習多線程"+i);
                              });
                          }
                      }

                      一個小練習:

                      //練習thread實現對線程同步下載圖片
                      public class TestThread2 extends Thread{
                      
                          private String url;
                          private String name;
                      
                          public TestThread2(String url, String name) {
                              this.url = url;
                              this.name = name;
                          }
                      
                          @Override
                          public void run() {
                                WebDownload webDownload=new WebDownload();
                                webDownload.downloader(url,name);
                                System.out.println("下載了文件名:"+name);
                          }
                      
                          public static void main(String[] args) {
                              TestThread2 t1=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","1.jpg");
                              TestThread2 t2=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","2.jpg");
                              TestThread2 t3=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","3.jpg");
                      
                              t1.start();
                              t2.start();
                              t3.start();
                      
                          }
                      }
                      
                      //下載器
                      class WebDownload{
                          //下載方法
                          public void downloader(String url,String name)  {
                              try {
                                  FileUtils.copyURLToFile(new URL(url),new File(name));
                              } catch (IOException e) {
                                  e.printStackTrace();
                                  System.out.println("IO異常,downloader方法出錯");
                              }
                          }
                      }

                      2.實現Runable接口

                      //創建線程的方法2:實現Runable接口
                      public class TestThread3 implements Runnable{
                      
                          @Override
                          public void run() {
                              //run()方法線程體
                              IntStream.range(0,20).forEach(i->{
                                  System.out.println("我在看代碼"+i);
                              });
                          }
                      
                          public static void main(String[] args) {
                              //創建一個線程對象
                              TestThread3 testThread3=new TestThread3();
                              //調用start()方法,啟動線程,不一定立即執行,由cpu調度執行
                      //        Thread thread=new Thread(testThread3);
                      //        thread.start();
                      
                              //或者這樣簡寫
                             new Thread(testThread3).start();
                              //主方法 main方法
                              IntStream.range(0,100).forEach(i->{
                                  System.out.println("我在學習多線程"+i);
                              });
                          }
                      }

                      如何學習Java多線程

                      理解并發的場景

                      當多個線程使用同一個資源時,會出現問題,看看下面這個買火車票的例子:

                      public class TestThread4 implements  Runnable{
                      
                          //票數
                          private int ticketNums=10;
                      
                          @Override
                          public void run() {
                              while(true){
                                  if (ticketNums<=0){
                                      break;
                                  }
                                  //模擬延遲
                                  try {
                                      Thread.sleep(200);
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                                  System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"張票");
                              }
                      
                          }
                      
                          public static void main(String[] args) {
                              TestThread4 ticket=new TestThread4();
                      
                              new Thread(ticket,"小明").start();
                              new Thread(ticket,"張三").start();
                              new Thread(ticket,"李四").start();
                          }
                      }

                      看看運行的結果:

                      如何學習Java多線程

                      可以看到案例中的線程不安全問題,同時數據也是不正確的

                      龜兔賽跑場景

                      /**
                       * 模擬龜兔賽跑
                       */
                      public class Race implements Runnable{
                          //勝利者
                          private static String winner;
                      
                          @Override
                          public void run() {
                      
                      
                              for (int i=0;i<=100;i++){
                                  //模擬兔子休息
                                  if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
                                      try {
                                          Thread.sleep(1);
                                      } catch (InterruptedException e) {
                                          e.printStackTrace();
                                      }
                                  }
                      
                                  boolean flag=gameOver(i);
                                  if (flag){  //判斷比賽是否結束
                                     break;
                                  }
                                  System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
                              }
                      
                          }
                      
                          /**
                           * 判斷比賽是否結束
                           */
                          private boolean gameOver(int steps){
                              //判斷是否有勝利者
                              if (winner !=null){
                                  //已經存在勝利者
                                  return true;
                              }else if (steps >= 100){
                                  winner=Thread.currentThread().getName();
                                  System.out.println("勝利者是:"+winner);
                                  return true;
                              }else{
                                  return false;
                              }
                          }
                      
                          public static void main(String[] args) {
                              Race race=new Race();
                              new Thread(race,"兔子").start();
                              new Thread(race,"烏龜").start();
                          }
                      }

                      實現callable接口

                      //線程創建方式3
                      public class TestCallable implements Callable<Boolean> {
                          private String url;
                          private String name;
                      
                          public TestCallable(String url, String name) {
                              this.url = url;
                              this.name = name;
                          }
                      
                          @Override
                          public Boolean call() {
                              com.sxh.thread.WebDownload webDownload=new com.sxh.thread.WebDownload();
                              webDownload.downloader(url,name);
                              System.out.println("下載了文件名:"+name);
                              return true;
                          }
                      
                          public static void main(String[] args) throws ExecutionException, InterruptedException {
                              TestCallable t1=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","1.jpg");
                              TestCallable t2=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","2.jpg");
                              TestCallable t3=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","3.jpg");
                      
                              //創建執行服務
                              ExecutorService ser= Executors.newFixedThreadPool(3);
                              //提交執行
                              Future<Boolean> r1=ser.submit(t1);
                              Future<Boolean> r2=ser.submit(t2);
                              Future<Boolean> r3=ser.submit(t3);
                              //獲取結果
                              boolean rs1=r1.get();
                              boolean rs2=r2.get();
                              boolean rs3=r3.get();
                              //關閉服務
                              ser.shutdownNow();
                          }
                      
                      }

                      理解函數式接口

                      任何接口,只包含唯一一個抽象方法,就是函數式接口

                      /**
                       * lambdab表達式的發展
                       */
                      public class TestLambda1 {
                          //3.靜態內部類
                          static class Like2 implements ILike{
                              @Override
                              public void lambda() {
                                  System.out.println("i like lambda2");
                              }
                          }
                      
                          public static void main(String[] args) {
                              ILike like=new Like();
                              like.lambda();
                      
                              like=new Like2();
                              like.lambda();
                      
                              //4.局部內部類
                             class Like3 implements ILike{
                                  @Override
                                  public void lambda() {
                                      System.out.println("i like lambda3");
                                  }
                              }
                              like=new Like3();
                              like.lambda();
                      
                              //5.匿名內部類
                              like=new ILike() {
                                  @Override
                                  public void lambda() {
                                      System.out.println("i like lambda4");
                                  }
                              };
                              like.lambda();
                      
                              //6.用lambda簡化
                              like=()->{
                                  System.out.println("i like lambda5");
                              };
                              like.lambda();
                          }
                      }
                      
                      //1.定義一個函數式接口
                      interface ILike{
                          void lambda();
                      }
                      
                      //2.實現類
                      class Like implements ILike{
                      
                          @Override
                          public void lambda() {
                              System.out.println("i like lambda");
                          }
                      }

                      理解線程的狀態

                      如何學習Java多線程

                      線程停止

                      public class TestStop implements Runnable{
                      
                          //1.設置一個標志位
                          private boolean flag=true;
                          @Override
                          public void run() {
                             int i=0;
                             while (flag){
                                 System.out.println("run...thread.."+i++);
                             }
                          }
                      
                          //2.設置一個公開的方法停止線程,轉換標志位
                          public void stop(){
                                 this.flag=false;
                          }
                      
                      
                          public static void main(String[] args) {
                              TestStop stop=new TestStop();
                              new Thread(stop).start();
                      
                      
                              for (int i = 0; i < 1000; i++) {
                                  System.out.println("main"+i);
                                  if (i==900){
                                      //調用stop方法,讓線程停止
                                      stop.stop();
                                      System.out.println("線程該停止了");
                                  }
                              }
                      //        IntStream.range(0,1000).forEach(i->{
                      //            
                      //        });
                          }
                      }

                      線程休眠sleep

                      每個對象都有一把鎖,sleep不會釋放鎖

                      1.網路延遲
                      //模擬延遲
                                  try {
                                      Thread.sleep(200); //ms
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                      2.倒計時等
                       public static void main(String[] args) {
                             try {
                                  tendown();
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                             }
                        }
                          public static void tendown() throws InterruptedException {
                              int num=10;
                              while (true){
                                  Thread.sleep(1000);
                                  System.out.println(num--);
                                  if(num<=0)
                                  {
                                      break;
                                  }
                              }
                          }
                       public static void main(String[] args) {
                              //打印系統當前時間
                              Date startTime=new Date(System.currentTimeMillis());
                              while (true){
                                  try {
                                      Thread.sleep(1000);
                                      System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                                      startTime=new Date(System.currentTimeMillis());//更新時間
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                              }
                          }

                      線程禮讓yield

                      //線程禮讓  禮讓不一定成功,由cpu重新調度
                      public class TestYield {
                          public static void main(String[] args) {
                              MyYield myYield=new MyYield();
                              new Thread(myYield,"a").start();
                              new Thread(myYield,"b").start();
                          }
                      }
                      class MyYield implements  Runnable{
                      
                          @Override
                          public void run() {
                              System.out.println(Thread.currentThread().getName()+"線程開始執行");
                              Thread.yield();
                              System.out.println(Thread.currentThread().getName()+"線程停止執行");
                          }
                      }

                      線程強制執行

                      //測試join方法  想象為插隊
                      public class TestJoin implements  Runnable{
                          @Override
                          public void run() {
                              for (int i = 0; i < 100; i++) {
                                  System.out.println("線程vip來了"+i);
                              }
                          }
                      
                          public static void main(String[] args) throws InterruptedException {
                              //啟動線程
                              TestJoin testJoin=new TestJoin();
                              Thread thread=new Thread(testJoin);
                              thread.start();
                      
                              //主線程
                              for (int i = 0; i < 1000; i++) {
                                  if (i==200){
                                      thread.join(); //插隊
                                  }
                                  System.out.println("main"+i);
                              }
                          }
                      }

                      觀察線程狀態

                      public class TestState {
                          public static void main(String[] args) throws InterruptedException {
                              Thread thread=new Thread(()->{
                                  for (int i = 0; i < 5; i++) {
                                      try {
                                          Thread.sleep(1000);
                                      } catch (InterruptedException e) {
                                          e.printStackTrace();
                                      }
                                  }
                                  System.out.println("//");
                              });
                      
                              //觀察狀態
                              Thread.State state=thread.getState();
                              System.out.println(state);   //NEW
                      
                              //啟動后
                              thread.start();
                              state=thread.getState();
                              System.out.println(state);   //Run
                      
                              while (state != Thread.State.TERMINATED)
                              {
                                  Thread.sleep(100);
                                  state=thread.getState();//更新線程狀態
                                  System.out.println(state);   //Run
                              }
                          }
                      }

                      線程的優先級

                      //測試線程的優先級
                      public class TestPriority {
                          public static void main(String[] args) {
                              //主線程默認優先級
                              System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
                      
                              MyPriority myPriority=new MyPriority();
                      
                              Thread t1=new Thread(myPriority);
                              Thread t2=new Thread(myPriority);
                              Thread t3=new Thread(myPriority);
                              Thread t4=new Thread(myPriority);
                              Thread t5=new Thread(myPriority);
                              Thread t6=new Thread(myPriority);
                              //先設置優先級,在啟動
                              t1.start();
                              t2.setPriority(1);
                              t2.start();
                              t3.setPriority(4);
                              t3.start();
                              t4.setPriority(Thread.MAX_PRIORITY);
                              t4.start();
                              t5.setPriority(-1);
                              t5.start();
                              t6.setPriority(11);
                              t6.start();
                      
                          }
                      }
                      class MyPriority implements Runnable{
                      
                          @Override
                          public void run() {
                              System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
                          }
                      }

                      守護線程

                      線程分為用戶線程和守護線程

                      //測試守護線程
                      public class TestDaemon {
                          public static void main(String[] args) {
                              God god=new God();
                              You you=new You();
                              Thread thread=new Thread(god);
                              thread.setDaemon(true); //默認是false表示用戶線程
                              thread.start();
                      
                              new Thread(you).start();
                      
                          }
                      }
                      
                      class God implements  Runnable{
                      
                          @Override
                          public void run() {
                            while (true){
                                System.out.println("上帝保佑著你");
                            }
                          }
                      }
                      class You implements Runnable{
                          @Override
                          public void run() {
                              for (int i = 0; i < 36000; i++) {
                                  System.out.println("你活著"+i);
                              }
                              System.out.println("goodbye!!");
                          }
                      }

                      線程同步機制

                      解決安全性問題:隊列+鎖

                      1.synchronized 同步方法

                      默認鎖的是this,如需鎖其他的,使用下面的同步塊

                      //synchronized 同步方法
                          private  synchronized void buy(){
                              if (ticketNums<=0){
                                  flag=false;
                                  return;
                              }
                              //模擬延遲
                              try {
                                  Thread.sleep(100);
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                              //買票
                              System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"張票");
                          }

                      2.同步塊synchronized(Obj){}

                      鎖的對象是變化的量,需要增刪改的對象
                      obj稱之為同步監視器,即監視對象

                      public class UnsafeList {
                          public static void main(String[] args) {
                              List<String> list=new ArrayList<String>();
                              for (int i = 0; i < 10000; i++) {
                                  new Thread(()->{
                                      synchronized (list){
                                          list.add(Thread.currentThread().getName());
                                      }
                                  }).start();
                              }
                      
                              try {
                                  Thread.sleep(3000);
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                              System.out.println(list.size());
                          }
                      }

                      lock

                      class A{
                           //ReentrantLock 可重入鎖
                           private final ReentrantLock lock=new ReentrantLock();
                           public void f(){
                             lock.lock();//加鎖
                             try{
                                 //.....
                              }
                             finally{
                                lock.unlock();//釋放鎖
                              }
                           }
                         
                      }

                      synchronized與lock

                      1. lock是顯示鎖需要手動開關,synchronized是隱式鎖,出了作用域自動釋放

                      2. lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖

                      3. JVM將花費更少的時間來調度線程,性能更好,更有擴展性

                      4. 優先使用:Lock>同步代碼塊>同步方法

                      到此,相信大家對“如何學習Java多線程”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

                      向AI問一下細節

                      免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

                      AI

                      亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女