久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

帶你通俗易懂的理解——線程、多線程與線程池

 codingSmart 2021-10-22

進(jìn)程與線程

  • 進(jìn)程:進(jìn)程就是正在執(zhí)行的程序,。

  • 線程:是程序執(zhí)行的一條路徑, 一個(gè)進(jìn)程中可以包含多條線程,。
    通俗理解:例如你打開微信就是打開一個(gè)進(jìn)程,在微信里面和好友視頻聊天就是開啟了一條線程,。

  • 兩者之間的關(guān)系
    一個(gè)進(jìn)程里面可以有多條線程,,至少有一條線程。
    一條線程一定會(huì)在一個(gè)進(jìn)程里面,。

關(guān)于進(jìn)程與線程的講解,,這篇文章講的挺好的-->進(jìn)程與線程的一個(gè)簡單解釋 http://www./blog/2013/04/processes_and_threads.html

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

一、繼承Thread

1、定義一個(gè)類MyThread繼承Thread,,并重寫run方法,。
2、將要執(zhí)行的代碼寫在run方法中,。
3,、創(chuàng)建該類的實(shí)例,并調(diào)用start()方法開啟線程,。


代碼如下:

public class MainActivity extends AppCompatActivity {
   private final String TAG = this.getClass().getSimpleName();
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       //3,、創(chuàng)建該類的實(shí)例,并調(diào)用start()方法開啟線程,。
       MyThread myThread = new MyThread();
       myThread.start();
   }
   //1,、定義一個(gè)類MyThread繼承Thread,并重寫run方法,。
   class MyThread extends Thread {
       public void run() {
           //2、將執(zhí)行的代碼寫在run方法中,。
           for (int i = 0; i < 100; i++) {
               Log.d(TAG, "線程名字:" + Thread.currentThread().getName()  + "  i=" + i);
           }
       }
   }
}
二,、實(shí)現(xiàn)Runnable接口

1、定義一個(gè)類MyRunnable實(shí)現(xiàn)Runnable接口,,并重寫run方法,。
2、將要執(zhí)行的代碼寫在run方法中,。
3,、創(chuàng)建Thread對(duì)象, 傳入MyRunnable的實(shí)例,并調(diào)用start()方法開啟線程,。


代碼如下:

public class MainActivity extends AppCompatActivity {
   private final String TAG = this.getClass().getSimpleName();
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       //3,、創(chuàng)建Thread對(duì)象, 傳入MyRunnable的實(shí)例,并調(diào)用start()方法開啟線程,。
       Thread thread = new Thread(new MyRunnable());
       thread.start();
   }
   //1,、定義一個(gè)類MyRunnable實(shí)現(xiàn)Runnable接口,并重寫run方法,。
   class MyRunnable implements Runnable {
       public void run() {
           //2,、將執(zhí)行的代碼寫在run方法中。
           for (int i = 0; i < 100; i++) {
               Log.d(TAG, "線程名字:" + Thread.currentThread().getName() + "  i=" + i);
           }
       }
   }
}
三,、實(shí)現(xiàn) Callable 接口

Callable 是類似于 Runnable 的接口,,實(shí)現(xiàn) Callable 接口的類和實(shí)現(xiàn) Runnable 的類都是可被其它線程執(zhí)行的任務(wù)。

1,、自定義一個(gè)類 MyCallable 實(shí)現(xiàn) Callable 接口,,并重寫call()方法
2、將要執(zhí)行的代碼寫在call()方法中
3,、創(chuàng)建線程池對(duì)象,,調(diào)用submit()方法執(zhí)行MyCallable任務(wù),,并返回Future對(duì)象
4、調(diào)用Future對(duì)象的get()方法獲取call()方法執(zhí)行完后的值


代碼如下:

public class MainActivity extends AppCompatActivity {
   private final String TAG = this.getClass().getSimpleName();
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       //3,、創(chuàng)建線程池對(duì)象,,調(diào)用submit()方法執(zhí)行MyCallable任務(wù),并返回Future對(duì)象
       ExecutorService pool = Executors.newSingleThreadExecutor();
       Future<Integer> f1 = pool.submit(new MyCallable());
       //4,、調(diào)用Future對(duì)象的get()方法獲取call()方法執(zhí)行完后的值
       try {
           Log.d(TAG, "sum=" + f1.get());
       } catch (InterruptedException e) {
           e.printStackTrace();
       } catch (ExecutionException e) {
           e.printStackTrace();
       }
       //關(guān)閉線程池
       pool.shutdown();
   }
   //1,、自定義一個(gè)類MyCallable實(shí)現(xiàn)Callable接口,并重寫call()方法
   public class MyCallable implements Callable<Integer> {
       @Override
       public Integer call() throws Exception {
           //2,、將要執(zhí)行的代碼寫在call()方法中
           int sum = 0;
           for (int i = 0; i <= 100; i++) {
               sum += i;
           }
           return sum;
       }
   }
}

創(chuàng)建線程的三種方式對(duì)比

一,、繼承 Thread 類與實(shí)現(xiàn) Runnable 接口的區(qū)別

我們都知道 java 支持單繼承,多實(shí)現(xiàn),。實(shí)現(xiàn) Runnable 接口還可以繼承其他類,,而使用繼承 Thread 就不能繼承其他類了。所以當(dāng)你想創(chuàng)建一個(gè)線程又希望繼承其他類的時(shí)候就該選擇實(shí)現(xiàn) Runnable 接口的方式,。

二,、實(shí)現(xiàn) Callable 接口與 Runnable 接口的區(qū)別

Callable 執(zhí)行的方法是 call() ,而 Runnable 執(zhí)行的方法是 run(),。
call() 方法有返回值還能拋出異常,, run() 方法則沒有沒有返回值,也不能拋出異常,。

多線程

一,、概念

一個(gè)進(jìn)程中開啟了不止一個(gè)線程。

二,、多線程的優(yōu)缺點(diǎn)
  • 優(yōu)點(diǎn)
    1,、提高CPU的使用率
    例如朋友圈發(fā)表圖片,當(dāng)你上傳9張圖片的時(shí)候,,如果開啟一個(gè)線程用同步的方式一張張上傳圖片,,假設(shè)每次上傳圖片的線程只占用了CPU 1%d的資源,剩下的99%資源就浪費(fèi)了,。但是如果你開啟9個(gè)線程同時(shí)上傳圖片,,CPU就可以使用9%的資源了。
    2,、提高程序的工作效率
    還是拿朋友圈發(fā)表圖片來說,,假設(shè)開啟一個(gè)線程上傳一張圖片的時(shí)間是1秒,那么同步的方式上傳9張就需要9秒,,但是你開啟9個(gè)線程同時(shí)上傳圖片,,那么就只需要1秒就完成了。

  • 缺點(diǎn)
    1、如果有大量的線程,會(huì)影響性能,因?yàn)镃PU需要在它們之間切換,。
    2,、更多的線程需要更多的內(nèi)存空間。
    3,、多線程操作可能會(huì)出現(xiàn)線程安全或者死鎖等問題,。

三、多線程并行和并發(fā)的區(qū)別
  • 概念
    并行:多個(gè)處理器或者多核處理器同時(shí)執(zhí)行多個(gè)不同的任務(wù),。
    并發(fā):一個(gè)處理器處理多個(gè)任務(wù),。

  • 打個(gè)比喻
    并行就是一個(gè)人用他的左手喂女兒吃飯,同時(shí)用右手喂兒子吃飯,。
    并發(fā)就是一個(gè)人先喂女兒吃一口飯,,接著喂兒子吃一口,然后再喂女兒吃一口,,輪流喂,。

  • 舉個(gè)多線程并發(fā)操作同一數(shù)據(jù)出現(xiàn)線程安全的例子
    利用多線程上傳9張圖片,并提示還剩幾張圖片未上傳,。代碼如下:

public class MainActivity extends AppCompatActivity {
   private final String TAG = this.getClass().getSimpleName();
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       //開啟2條線程上傳圖片
       MyRunnable myRunnable = new MyRunnable();
       new Thread(myRunnable, "線程1").start();
       new Thread(myRunnable, "線程2").start();
   }
   public class MyRunnable implements Runnable {
       private int imgNum = 9;//圖片數(shù)量
       @Override
       public void run() {
           while (true) {
               if (imgNum == 0) {
                   break;
               }
               try {
                   Thread.sleep(1000);//模擬上傳一張圖片需要1秒鐘的時(shí)間
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               Log.d(TAG, Thread.currentThread().getName() + "正在上傳圖片...,,還剩" + imgNum-- + "張圖片未上傳");
           }
       }
   }
}

打印結(jié)果如下:

由圖可知,圖片數(shù)量出現(xiàn)了負(fù)數(shù),,顯然是錯(cuò)誤的,。

原因:
出現(xiàn)這種錯(cuò)誤的原因是有多個(gè)線程在操作共享的數(shù)據(jù),。即一個(gè)線程在操作共享數(shù)據(jù)的過程中CPU切換到其他線程又對(duì)該數(shù)據(jù)進(jìn)行操作,,這就是所謂的多線程并發(fā)。

解決:
把操作數(shù)據(jù)的那段代碼用 synchronized 進(jìn)行同步, 這樣就能保證在同一時(shí)刻只能有一個(gè)線程能夠訪問,。


代碼如下:

public class MainActivity extends AppCompatActivity {
   private final String TAG = this.getClass().getSimpleName();
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       //開啟2條線程上傳圖片
       MyRunnable myRunnable = new MyRunnable();
       new Thread(myRunnable, "線程1").start();
       new Thread(myRunnable, "線程2").start();
   }
   public class MyRunnable implements Runnable {
       private int imgNum = 9;//圖片數(shù)量
       @Override
       public void run() {
           while (true) {
               synchronized (MyRunnable.class) { //加上synchronized進(jìn)行同步,,保證在同一時(shí)刻只能有一個(gè)線程能夠訪問。
                   if (imgNum == 0) {
                       break;
                   }
                   try {
                       Thread.sleep(1000);//模擬上傳一張圖片需要1秒鐘的時(shí)間
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   Log.d(TAG, Thread.currentThread().getName() + "正在上傳圖片...,,還剩" + imgNum-- + "張圖片未上傳");
               }
           }
       }
   }
}

打印結(jié)果如下:

線程池

關(guān)于線程池

前面舉的朋友圈發(fā)表圖片的多線程例子中,,為了提高CPU的使用率和程序的工作效率就需要?jiǎng)?chuàng)建9個(gè)線程來上傳圖片。但是線程的創(chuàng)建和銷毀是非常耗CPU和內(nèi)存的,,因?yàn)樗婕暗揭c操作系統(tǒng)進(jìn)行交互,。這樣就可能導(dǎo)致創(chuàng)建與銷毀線程的開銷比實(shí)際業(yè)務(wù)還大,而線程池就能很好的解決這些問題,。線程池里的每一個(gè)線程結(jié)束后,,并不會(huì)銷毀(可以設(shè)置超時(shí)銷毀),而是回到線程池中成為空閑狀態(tài),,等待下一個(gè)對(duì)象來使用,。

使用線程池的優(yōu)點(diǎn)

1、減少創(chuàng)建與銷毀線程帶來的性能開銷。
2,、可控制最大并發(fā)線程數(shù),,避免過多資源競爭而導(dǎo)致系統(tǒng)內(nèi)存消耗完。
3,、能更好的控制線程的開啟與回收,,并且能定時(shí)執(zhí)行任務(wù)。

線程池中重要的幾個(gè)類
  • Executor:java中線程池的頂級(jí)接口,,可以稱它為一個(gè)執(zhí)行器,,通過查看源碼也知道,他只有一個(gè)簡單的方法execute(Runnable command),,就是用來執(zhí)行提交的任務(wù),。源碼如下:
    【Executor.java】

public interface Executor {
   void execute(Runnable command);
}
  • ExecutorService:Executor的子類,也是真正的線程池接口,。它提供了提交任務(wù)和關(guān)閉線程池等方法,。調(diào)用submit方法提交任務(wù)還可以返回一個(gè)Future對(duì)象,利用該對(duì)象可以了解任務(wù)執(zhí)行情況,,獲得任務(wù)的執(zhí)行結(jié)果或取消任務(wù),。

  • Executors:由于線程池配置比較復(fù)雜,自己配置的線程池可能性能不是最好的,。Executors就是用來方便創(chuàng)建各種常用線程池的工具類,。

  • ThreadPoolExecutor:ExecutorService的默認(rèn)實(shí)現(xiàn),Executors創(chuàng)建各種線程池的時(shí)候內(nèi)部其實(shí)就是調(diào)用了ThreadPoolExecutor的構(gòu)造方法,。下面通過查看源碼驗(yàn)證,。
    例如隨便創(chuàng)建一個(gè)線程池:

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

點(diǎn)擊newCachedThreadPool()進(jìn)去,里面確實(shí)調(diào)用了ThreadPoolExecutor的構(gòu)造方法,,如下:
【Executor.java】

   public static ExecutorService newCachedThreadPool() {
       return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                     60L, TimeUnit.SECONDS,
                                     new SynchronousQueue<Runnable>());
   }
ThreadPoolExecutor構(gòu)造函數(shù)參數(shù)說明

下面從源碼中拿一個(gè)參數(shù)最完整的來講解,,如下:
【ThreadPoolExecutor.java】

   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue,
                             ThreadFactory threadFactory,
                             RejectedExecutionHandler handler)
{
   }
  • corePoolSize:核心線程數(shù),如果運(yùn)行的線程數(shù)少于corePoolSize,,當(dāng)有新的任務(wù)過來時(shí)會(huì)創(chuàng)建新的線程來執(zhí)行這個(gè)任務(wù),,即使線程池中有其他空閑的線程。

  • maximumPoolSize:線程池中允許的最大線程數(shù),。

  • keepAliveTime:如果線程數(shù)多于核心線程數(shù),,那么這些多出來的線程如果空閑時(shí)間超過keepAliveTime將會(huì)被終止。

  • unit:keepAliveTime參數(shù)的時(shí)間單位,。

  • workQueue:任務(wù)隊(duì)列,,通過線程池的execute方法會(huì)將任務(wù)Runnable存儲(chǔ)在隊(duì)列中。

  • threadFactory:線程工廠,,用來創(chuàng)建新線程,。

  • handler:添加任務(wù)出錯(cuò)時(shí)的策略捕獲器,,默認(rèn)是ThreadPoolExecutor.AbortPolicy ,即添加任務(wù)出錯(cuò)就直接拋出異常 ,。

四種線程池
  • newFixedThreadPool:創(chuàng)建固定大小的線程池,,這樣可以控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待,。如果線程池中的某個(gè)線程由于異常而結(jié)束,,線程池則會(huì)再補(bǔ)充一條新線程。
    例子:創(chuàng)建線程數(shù)為3的線程池

       ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
       for (int i = 0; i < 10; i++) {
           final int finalI = i;
           newFixedThreadPool.execute(new Runnable() {
               @Override
               public void run() {
                   try {
                       Thread.sleep(1000);
                       Log.d(TAG, "線程名字:" + Thread.currentThread().getName() + "  i=" + finalI);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
           });
       }

打印結(jié)果:

由打印結(jié)果可知,,10個(gè)任務(wù)始終在3個(gè)線程中執(zhí)行,。

  • newSingleThreadExecutor:創(chuàng)建一個(gè)單線程的線程池,即這個(gè)線程池永遠(yuǎn)只有一個(gè)線程在運(yùn)行,,這樣能保證所有任務(wù)按指定順序來執(zhí)行,。如果這個(gè)線程異常結(jié)束,那么會(huì)有一個(gè)新的線程來替代它,。


    例子:

       ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
       for (int i = 0; i < 10; i++) {
           final int finalI = i;
           newSingleThreadExecutor.execute(new Runnable() {
               @Override
               public void run() {
                   try {
                       Thread.sleep(1000);
                       Log.d(TAG, "線程名字:" + Thread.currentThread().getName() + "  i=" + finalI);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
           });
       }

打印結(jié)果:

由打印結(jié)果可知,,10個(gè)任務(wù)始終在3個(gè)線程中執(zhí)行。

  • newCachedThreadPool:創(chuàng)建帶有緩存的線程池,,在執(zhí)行新的任務(wù)時(shí),,當(dāng)線程池中有之前創(chuàng)建的可用線程就重用之前的線程,否則就新建一條線程,。如果線程池中的線程在60秒未被使用,,就會(huì)將它從線程池中移除。
    例子:

       ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
       for (int i = 0; i < 10; i++) {
           final int finalI = i;
           newCachedThreadPool.execute(new Runnable() {
               @Override
               public void run() {
                   Log.d(TAG, "線程名字:" + Thread.currentThread().getName() + "  i=" + finalI);
               }
           });
       }

由打印結(jié)果可知,,線程1出現(xiàn)了很多次,,說明有重用之前創(chuàng)建的線程。

  • newScheduledThreadPool:創(chuàng)建定時(shí)和周期性執(zhí)行的線程池,。

       ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3);
       /**
        * 延遲2秒執(zhí)行任務(wù)
        */

       newScheduledThreadPool.schedule(new Runnable() {
           @Override
           public void run()
{
               Log.d(TAG, "線程名字:" + Thread.currentThread().getName() + "定時(shí)任務(wù)");
           }
       }, 2, TimeUnit.SECONDS);
       /**
        * 延遲1秒后每2秒執(zhí)行一次任務(wù)
        */

       newScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
           @Override
           public void run()
{
               Log.d(TAG, "線程名字:" + Thread.currentThread().getName() + "周期性任務(wù)");
           }
       }, 1, 2, TimeUnit.SECONDS);

由打印結(jié)果可知,,定時(shí)任務(wù)是 2 秒后執(zhí)行任務(wù),,周期性任務(wù)是延遲 1 秒后每 2 秒執(zhí)行一次任務(wù),。

與之相關(guān)

6 天時(shí)間修改 1 行代碼:現(xiàn)實(shí)中的軟件開發(fā)流程

如何有效報(bào)告 bug

贊助商

優(yōu)秀人才不缺工作機(jī)會(huì),只缺適合自己的好機(jī)會(huì),。但是他們往往沒有精力從海量機(jī)會(huì)中找到最適合的那個(gè),。100offer 會(huì)對(duì)平臺(tái)上的人才和企業(yè)進(jìn)行嚴(yán)格篩選,讓「最好的人才」和「最好的公司」相遇,。掃描下方二維碼,,注冊(cè) 100offer,談?wù)勀銓?duì)下一份工作的期待,。一周內(nèi),,收到 5-10 個(gè)滿足你要求的好機(jī)會(huì),!

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多