Java手書きスレッドプール-第1世代(オリジナル)

個人プロフィール

著者は河源の3年生です。以下のメモは、独学の道での著者の表面的な経験です。間違いがあれば訂正してください。今後もメモを改善していきます。より多くのJava愛好家が始めるのを助けるために。

Java手書きスレッドプール(第1世代)

  • スレッドプールはよく使われるので、今日、気まぐれでスレッドプールを手で書くことには多くの欠点があります。もっと寛容にしてください。これは第1世代のバージョンでもあるため、フォローアップはより完璧になります。

手書きのスレッドプール-パラメータを定義する

	private final AtomicInteger taskcount=new AtomicInteger(0);
    private final AtomicInteger threadNumber=new AtomicInteger(0);
    private volatile int corePoolSize; 
    private final Set<MyThreadPoolExecutor.MyWorker> workers; 
    private final BlockingQueue<Runnable> waitingQueue; 
    private final String THREADPOOL_NAME="MyThread-Pool-";
    private volatile boolean isRunning=true; 
    private volatile boolean STOPNOW=false; 
    private final ThreadFactory threadFactory; 

taskcount:実行されるタスクの数
threadNumber:0から始まり、順番に増加するスレッド番号。
corePoolSize:コアスレッドの数
worker:ワーカースレッド
waitingQueue:待機キュー
THREADPOOL_NAME:スレッド名
isRunning:実行するかどうかSTOPNOW:
すぐに停止するかどうか
threadFactory:スレッドファクトリ

手書きのスレッドプール-コンストラクター

    public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) {
    
    
        this.corePoolSize=corePoolSize;
        this.workers=new HashSet<>(corePoolSize);
        this.waitingQueue=waitingQueue;
        this.threadFactory=threadFactory;
        //线程预热
        for (int i = 0; i < corePoolSize; i++) {
    
    
            new MyWorker();
        }
    }
  • このコンストラクターは機能します:
  • 1:パラメータに値を割り当てます。
  • 2:スレッドのウォームアップ。MyWorkerのコンストラクターは、corePoolSizeのサイズに従って呼び出されます。MyWorkerコンストラクターが何をするかを見ることができます。
	final Thread thread; //为每个MyWorker

        MyWorker(){
    
    
            Thread td = threadFactory.newThread(this);
            td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement());
            this.thread=td;
            this.thread.start();
            workers.add(this);
        }
  • MyWorkerコンストラクターは、スレッドファクトリを介して現在のオブジェクトのスレッドを生成します。
  • そして、スレッド名:MyThread-Pool-自己インクリメントスレッド番号;
  • 次に、スレッドのstartメソッドを呼び出してスレッドを開始します。
  • 最後に、ワーカーのSetコレクションに格納されるため、スレッドの再利用を実現できます。

手書きのスレッドプール-デフォルトのコンストラクター

	public MyThreadPoolExecutor(){
    
    
        this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory());
    }
  • デフォルトの初期化子の割り当て
  • corePoolSize:5
  • waitingQueue:新しいArrayBlockingQueue <>(10)、長さ10の有限ブロッキングキュー
  • threadFactory:Executors.defaultThreadFactory()

手書きのスレッドプール-executeメソッド

	public boolean execute(Runnable runnable)
    {
    
    
        return waitingQueue.offer(runnable);
    }
  • 本質的には、Runnable(タスク)をwaitingQueueに配置することです

手書きのスレッドプール-処理タスク

	   @Override
        public void run() {
    
    
            //循环接收任务
                while (true)
                {
    
    
                    if((!isRunning&&waitingQueue.size()==0)||STOPNOW)
                    {
    
    
                        break;
                    }else {
    
    
                        Runnable runnable = waitingQueue.poll();
                        if(runnable!=null){
    
    
                            runnable.run();
                            System.out.println("task==>"+taskcount.incrementAndGet());
                        }
                    }
                }
        }
  • 本質的に、これは無限ループ受信タスクであり、終了条件は次のとおりです。
  • 1:正常に終了します。isRunningがfalseで、waitingQueueのキューサイズが0の場合(つまり、タスクがない場合)
  • 2:暴力的な出口。STOPNOWがtrueの場合、shutdownNowメソッドが呼び出されます
  • elseステートメントブロックは、タスクが実行されると、引き続きタスクを実行します。= null、runメソッドを呼び出してタスクを処理します

手書きのスレッドプール-スレッドプールを適切に閉じます

	public void shutdown()
    {
    
    
        this.isRunning=false;
    }

手書きのスレッドプール-スレッドプールを激しく閉じます

	public void shutdownNow()
    {
    
    
        this.STOPNOW=true;
    }

手書きのスレッドプール-ソースコード

手書きスレッドプールクラスのソースコード

package com.springframework.concurrent;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池类
 * @author 游政杰
 */
public class MyThreadPoolExecutor {
    
    

    private final AtomicInteger taskcount=new AtomicInteger(0);//执行任务次数
    private final AtomicInteger threadNumber=new AtomicInteger(0); //线程编号
    private volatile int corePoolSize; //核心线程数
    private final Set<MyThreadPoolExecutor.MyWorker> workers; //工作线程
    private final BlockingQueue<Runnable> waitingQueue; //等待队列
    private final String THREADPOOL_NAME="MyThread-Pool-";//线程名称
    private volatile boolean isRunning=true; //是否运行
    private volatile boolean STOPNOW=false; //是否立刻停止
    private final ThreadFactory threadFactory; //线程工厂

    public MyThreadPoolExecutor(){
    
    
        this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory());
    }

    public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) {
    
    
        this.corePoolSize=corePoolSize;
        this.workers=new HashSet<>(corePoolSize);
        this.waitingQueue=waitingQueue;
        this.threadFactory=threadFactory;
        //线程预热
        for (int i = 0; i < corePoolSize; i++) {
    
    
            new MyWorker();
        }
    }

    /**
     * MyWorker就是我们每一个线程对象
     */
    private final class MyWorker implements Runnable{
    
    

        final Thread thread; //为每个MyWorker

        MyWorker(){
    
    
            Thread td = threadFactory.newThread(this);
            td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement());
            this.thread=td;
            this.thread.start();
            workers.add(this);
        }

        @Override
        public void run() {
    
    
            //循环接收任务
                while (true)
                {
    
    
                    //循环退出条件:
                    //1:当isRunning为false并且waitingQueue的队列大小为0(也就是无任务了),会优雅的退出。
                    //2:当STOPNOW为true,则说明调用了shutdownNow方法进行暴力退出。
                    if((!isRunning&&waitingQueue.size()==0)||STOPNOW)
                    {
    
    
                        break;
                    }else {
    
    
                        //不断取任务,当任务!=null时则调用run方法处理任务
                        Runnable runnable = waitingQueue.poll();
                        if(runnable!=null){
    
    
                            runnable.run();
                            System.out.println("task==>"+taskcount.incrementAndGet());
                        }
                    }
                }
        }
    }

    public boolean execute(Runnable runnable)
    {
    
    
        return waitingQueue.offer(runnable);
    }
    //优雅的关闭
    public void shutdown()
    {
    
    
        this.isRunning=false;
    }
    //暴力关闭
    public void shutdownNow()
    {
    
    
        this.STOPNOW=true;
    }
}

手書きのスレッドプールコードを使用してテストする

package com.springframework.test;

import com.springframework.concurrent.MyThreadPoolExecutor;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;

public class ThreadPoolTest {
    
    

  public static void main(String[] args) {
    
    

    
      MyThreadPoolExecutor myThreadPoolExecutor = new MyThreadPoolExecutor
              (5,new ArrayBlockingQueue<>(6), Executors.defaultThreadFactory());

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

          int finalI = i;
          myThreadPoolExecutor.execute(()->{
    
    
              System.out.println(Thread.currentThread().getName()+">>>>"+ finalI);
          });

      }

      myThreadPoolExecutor.shutdown();

//      myThreadPoolExecutor.shutdownNow();



  }
}

質問:カスタムスレッドプールの実行によって実行されるタスクが減少することがあるのはなぜですか?

  • これは、waitingQueueがいっぱいでタスクを停止できないため、タスクが破棄されるためです。これは、DiscardPolicy拒否ポリシーと同等です。
    • ソリューションは次のとおりです。
    • 1:スレッドプールを自動的に拡張するスレッドの最大数を設定します。
    • 2:waitingQueueの容量を増やします

最後に:これは私の手書きスレッドプールの第1世代バージョンであるため、基本的にスレッドプールの再利用機能を実装しますが、まだ多くの欠陥があります。将来的には、現在のスレッドプールをアップグレードするためにさらにいくつかの改善された記事があります手書きのスレッドプール。

フォローアップでは、著者の手書きのSpringフレームワーク、手書きのTomcat、およびその他のフレームワークに関するブログ投稿を引き続き公開します。

おすすめ

転載: blog.csdn.net/weixin_50071998/article/details/123583632