焼き方言の深いJavaスレッドプール - 妹プログラマには彼女がいたスレッドプールを実装して......

前面に書かれました

スレッドプールは、高周波テストサイトにインタビューされ、これは入り口として、ソースPaの選択、作成した2つの戦闘スレッドプールを決定してのRejectedExecutionHandlerを選択するために、実行スレッドプール、スレッドプールを説明するの方言は、スレッドプールからポリシーを拒否するもの飽和しています。

はじめにスレッドプール

背景を使用します。

  • 私たちは、プロジェクト内で実行する複数のスレッドを使用するようにコードの多くを持っている場合
  • 単独のコンピュータのCPUのハードウェアリソースは、同時に複数のスレッドの破壊を作成しません場合には

スレッドプールの出演:

  • たとえば、スレッドプールは、銀行カウンター理解できるでお金を節約するために:人々はお金を節約するために企業のためのスレッドカウンターのような銀行に行きたいが、スレッドプールは、銀行のカウンターウィンドウですが、銀行は単にウィンドウすることはできません、ウィンドウの数ですウィンドウには、勤務中の銀行員が毎日もリーダーシップによって決定されている(スレッドプールmaximumPoolSizeパラメータのようなものです)銀行のリーダーシップによって決定されるので、開口部は、(スレッドプールのようなものですcorePoolSizeパラメータ)を限定されています。

なぜ直接スレッドを作成するのではなく、スレッドプールを使用します。

  • 上記の例に従って引用して、その後、誰かが銀行の申請を希望する直接のようなコードを実行するスレッドを作成し、銀行は販売の限られた数との契約が不十分になると数を掛けた後、行うには彼を与えるために、セールスマンの手配を飛びましたそれぞれの人のためのビジネス・プロセスなので、遅かれ早かれ冷え、銀行を開きます。
  • そして、スレッドプールとのビジネスをしたいですが、多くの人がカウンターにそれを回す適用することができるようになり、ビジネスを行うことである完全なビジネス・プロセス、目の前で待機するために、他の顧客の窓に満ちている、セールスマンは、より多くのビジネスを扱うことができるようになりますその限られた資源(店員)と無制限の事業(顧客)に着手します。

スレッドプールの理由を選択

JDKは以下を提供します。

  • FixedThreadPool
  • CachedThreadPool(弾性キャッシングスレッドプール)
  • SingleThreadPool(単一スレッドのスレッドプール)
  • ScheduledThreadpool(タイマースレッドプール)
  • 四つのスレッドプールの種類ではなく、使いやすいが、私は特定のソースによって分析しました。

FixedThreadPool

  • Executors.java
    -newFixedThreadPool()方法
   /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

あなたはFixedThreadPoolが待機キュースレッドプールとしてLinkedBlockingQueue()に戻って作成する方法を見ることができますので、私たちはLinkedBlockingQueueをフォローアップ。

  • LinkedBlockingQueue.java
//这是LinkedBlockingQueue的插入方法,可以看到只要线程数少于capacity这个变量那么都可以进入队列,这时我们找到这个变量的具体数字为多少
    public boolean offer(E e) {
        if (e == null) throw new NullPointerException();
        final AtomicInteger count = this.count;
        if (count.get() == capacity)
            return false;
        int c = -1;
        Node<E> node = new Node<E>(e);
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            if (count.get() < capacity) {
                enqueue(node);
                c = count.getAndIncrement();
                if (c + 1 < capacity)
                    notFull.signal();
            }
        } finally {
            putLock.unlock();
        }
        if (c == 0)
            signalNotEmpty();
        return c >= 0;
    }
==================================================================
可以见到这个数字的最大值是int的最大值
================================================================
 /** The capacity bound, or Integer.MAX_VALUE if none */
    private final int capacity;

コードによれば、このスレッドプールの使用は、その後、ほとんどのスレッドキューにキューを入力することができた場合、それは要求の多くを蓄積することがわかります。

SingleThreadPool
セクションFixedThreadPool解決など、このスレッド・プールの待ちキューとFixedThreadPool。

CachedThreadPool和ScheduledThreadpool

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
=========================================================================
      public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
       
    }
    }
    }

スレッドプール内のスレッドの最大数は、これらの二つの創造にInteger.MAX_VALUEであることができ、これがOOMにつながります。

スレッドプールの実行プロセス

スレッドプール
最初のステップは、コードを実行するために割り当てられた描画、スレッドプールとスレッドプールスレッドの作業に基づいてコードを受信するであろう
maximumPoolSize>要求の数> corePoolSizeスレッドプールスレッドを呼び出すコードを作成する場合1.
2.リクエスト数> maximumPoolSize次いで場合要求が待ちキューのBlockingQueueに入れられます
リクエストはリクエストキューが待機キューとスレッドプールでいっぱいになるまで蓄積し続けた場合3.まだアイドルスレッドではありません
、それは、スレッドプールの飽和拒否戦略が発生しますのRejectedExecutionHandler、デフォルトではAbortPolicy(あります例外がスローされます)

四の飽和がポリシーの解決を拒否しました

1、AbortPolicy:直接スロー例外

2、CallerRunsPolicy:だけのスレッド実行中のタスクがどこ呼び出します

3、DiscardOldestPolicy:廃棄最近のタスクをキューイングし、現在のタスクを実行します。

4、DiscardPolicy:無処理、廃棄されました。

実1:スレッドプールの実装

最高の生産では、スレッドプールを作成するための彼の呼び出しですThreadPoolExecutor

/*创建一个线程池
*
*  corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,
* 等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
    runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。
       maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,4
    则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

·        ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

·        RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,
        那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。

     keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多
        并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。

·        TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),秒(SECONDS),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

* */
public class threadPoolDemo {
    static int maxNumberOfThreadPool=3;
    public static void main(String[] args)  {
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2,3,1L,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(2),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
        //这里设置成6个任务需要线程池执行
        //但是线程池最大为3 且阻塞队列最大为2 所以线程池就会拒绝
        for (int i = 0; i <=5 ; i++) {
            System.out.println("线程\t"+i+"\t正在提交到线程池中执行");
            try{
                threadPoolExecutor.execute(new ThreadDemo("工作"+(i+1)));
            }
            catch (Exception e)
            {
//                threadPoolExecutor.
                try {
                    threadPoolExecutor.awaitTermination(3,TimeUnit.SECONDS);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
                    System.out.println(Thread.currentThread().getName()+"\t"+"线程池因为没有空余线程以及阻塞队列也满了所以"+"工作"+(i+1)+"拒绝执行");
            }
        }
        threadPoolExecutor.shutdown();
    }
}

class  ThreadDemo implements  Runnable
{
    String threadName=null;
    public ThreadDemo(String threadName) {
        this.threadName = threadName;
    }
    @Override
    public void run() {
        System.out.println(threadName+"被\t"+Thread.currentThread().getName()+"\t执行了");
       try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(threadName+"\t执行完毕");
    }
}

======================================================================
运行结果:
*线程	0	正在提交到线程池中执行
线程	1	正在提交到线程池中执行
线程	2	正在提交到线程池中执行
线程	3	正在提交到线程池中执行
线程	4	正在提交到线程池中执行
工作1被	pool-1-thread-1	执行了
线程	5	正在提交到线程池中执行
工作2被	pool-1-thread-2	执行了
工作5被	pool-1-thread-3	执行了
工作2	执行完毕
工作5	执行完毕
工作1	执行完毕
工作3被	pool-1-thread-3	执行了
工作4被	pool-1-thread-2	执行了
**********************************************************
main	线程池因为没有空余线程以及阻塞队列也满了所以工作6拒绝执行
java.util.concurrent.RejectedExecutionException: Task ThreadPool.ThreadDemo@5caf905d rejected from java.util.concurrent.ThreadPoolExecutor@27716f4[Running, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at ThreadPool.threadPoolDemo.main(threadPoolDemo.java:39)
********************************************************
工作4	执行完毕
工作3	执行完毕

デフォルトのポリシーの結果から分かるようにスローされます。

戦闘2のRejectedExecutionHandler飽和は、選択ポリシーを拒否する

新しいThreadPoolExecutor.DiscardPolicy()

ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor
(2,3,1L,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());

运行结果:
* 线程	0	正在提交到线程池中执行
线程	1	正在提交到线程池中执行
线程	2	正在提交到线程池中执行
线程	3	正在提交到线程池中执行
线程	4	正在提交到线程池中执行
工作1被	pool-1-thread-1	执行了
工作2被	pool-1-thread-2	执行了
线程	5	正在提交到线程池中执行
工作5被	pool-1-thread-3	执行了
工作1	执行完毕
工作2	执行完毕
工作3被	pool-1-thread-2	执行了
工作4被	pool-1-thread-1	执行了
工作5	执行完毕
工作4	执行完毕
工作3	执行完毕

そこにスレッドプール内のアイドルスレッドがありませんし、キューがいっぱいになっているので、のRejectedExecutionHandler戦略に従って破棄されるので、6あなたは仕事を見ることができます。

新しいThreadPoolExecutor.DiscardOldestPolicy()

ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor
(2,3,1L,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy());


该策略是丢弃在队列种等待最久的线程并将此线程再次提交
线程	0	正在提交到线程池中执行
线程	1	正在提交到线程池中执行
线程	2	正在提交到线程池中执行
线程	3	正在提交到线程池中执行
工作1被	pool-1-thread-1	执行了
线程	4	正在提交到线程池中执行
工作2被	pool-1-thread-2	执行了
线程	5	正在提交到线程池中执行
工作5被	pool-1-thread-3	执行了

工作5	执行完毕
工作2	执行完毕
工作1	执行完毕
工作4被	pool-1-thread-3	执行了
工作6被	pool-1-thread-1	执行了

工作6	执行完毕
工作4	执行完毕
*********************************
* 线程3被丢弃了 因为选用了等待时间长就丢弃的饱和拒绝策略
* **********************************
    

新しいThreadPoolExecutor.CallerRunsPolicy()

ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor
(2,3,1L,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(2),
Executors.defaultThreadFactory(),
new new ThreadPoolExecutor.CallerRunsPolicy());


线程	0	正在提交到线程池中执行
线程	1	正在提交到线程池中执行
线程	2	正在提交到线程池中执行
线程	3	正在提交到线程池中执行
工作1被	pool-1-thread-1	执行了
线程	4	正在提交到线程池中执行
工作2被	pool-1-thread-2	执行了
线程	5	正在提交到线程池中执行
***************************
工作6被	main	执行了
*****************************
工作5被	pool-1-thread-3	执行了
工作6	执行完毕
工作5	执行完毕
工作2	执行完毕
工作1	执行完毕
工作3被	pool-1-thread-3	执行了
工作4被	pool-1-thread-1	执行了
工作4	执行完毕
工作3	执行完毕
    

おすすめ

転載: blog.csdn.net/qq_38404698/article/details/93612147