`

图说 ThreadPoolExecutor 和 Lock 原理

阅读更多

ThreadPoolExecutor :  创建一个 thread pool, pool 中每个 thread 称为 worker,负责执行任务(Task), task个数如果不大于线程池的个数,则分别分给线程池里的各个线程,否则 task 入队列, worker 执行完自己 task,去队列取新任务执行。直到队列里面没有任务,park 住线程池中的线程。

 

AQS : tryAcquire(),尝试让当前线程获得锁,获得则设置当前线程为执行线程,返回 true,否则返回 false.

              acquire(),让当前线程获得锁,如获得,直接执行当前线程。 否则包装当前线程为 Node,进入等待队列,同时设置前驱 prep 的 status 为 -1,表示前驱出队列时会激活自己,通过 LockSupport.park 刮起自己。

              tryRelease,尝试释放锁。

              release(),释放锁。

 

Sync :  lock(),

 

if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);

               unlock(),

 

sync.release(1);

 Condition : 与 lock 关联, conditon = lock.newCondition(), 通过 condition.await()让当前线程进入condition等待队列 (注:与线程等待队列 区别,前者通过 prep, next 联系,后者通过 nextWaiter联系 ),一个锁的每个 condition 都可能有自己的 condition 队列,所以一个锁,含有n个 condition,共可能有 1+n个队列。当收到 condition.single()时,condition 线程从 condition 队列加入到 线程等待队列尾部,等待以后执行。

 

CountDownLatch CountDownLatch(n) , 即:首先加上 n把锁 ,以后每个 CountDownLatch 使用线程可以 通过 countDown减掉一把锁,同时 LockSupport.park 该线程,所以只有减最后一把锁的时候,才会释放占有的资源 ,LockSupport.unpark 锁定的线程。因此等待队列的一个线程可能有两个地方激活他:1,最后一把锁释放时候激活等待队列的所有该锁的等待线程。 2,最后一把锁释放,激活等待队列的该锁的第一个等待线程,该线程激活后继线程。

 

CyclicBarrier : 类似 CountDownLatch,CyclicBarrier(n) --> 表示 acquire(n),首先加上 n 把锁 ,但是用另外一个变量保存锁的个数 ,这样每个CyclicBarrier使用线程可以通过 await() 减去一把锁,同时 LockSupport.park 该线程,直到最后一把锁减去时, LockSuport.unpark 所有锁定线程 ,同时:重置锁的个数为 n ,再次循环上面过程。

 

 

Semaphore Semaphore(n) ,首先表示资源最多可以有 n把锁同时使用才能锁上,与CountDownLatch和CyclicBarrier 最大区别为 前者的锁为并联 ,只要有一把锁就锁定资源 Semaphore 为串连 ,只有所有锁都锁上,才能锁住 资源,acquire();表示加上一把锁,release()表示释放一把锁,其他线程可以立即获得该锁。 所以 Semaphore(1),跟 Lock 功能类似。

 

FutureTask 执行完任务返回 。使用 Callable()执行,而线程 Callable() 执行可以返回结果。 所以可以通过设置当前线程执行者runner,和执行线程 Callable 状态表示执行的线程是否完成。 例如: Callable 返回结果,并且 runner为null , 则该线程执行结束。

 

下图部分为 ThreadPoolExecutor 一个演示过程(注:该图只是一种可能结果,因为线程执行的不确定性),部分为 Lock的演示过程。

  • 大小: 391.8 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics