android http 线程池,Okhttp的线程池

2021年第一篇文章~~

线程池策略

当一个任务通过execute(Runnable)方法添加到线程池时:

线程数量小于corePoolSize,新建线程数来处理被添加的任务。

线程数量大于等于corePoolSize,存在空闲线程,使用空闲线程执行新任务。

线程数量大于等于corePoolSize,不存在空闲线程,新任务被添加到等待队列,添加成功则等待空闲线程;

添加失败:线程数量小于最大线程数,新建线程执行新任务;线程数量等于最大线程数,则拒绝此任务。

Okhttp线程池配置1

2

3

4

5

6

7public synchronized ExecutorService executorService() {

if (executorService == null) {

executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));

}

return executorService;

}

可以看出,创建的线程池核心线程数为0,最大线程数MAX_VALUE,闲置时间60s,队列SynchronousQueue。这样的参数配置出来的线程池高并发,最大吞吐量。

那么为什么Okhttp的线程池队列用的SynchronousQueue而不是其他的?我们先看个栗子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30public void testQueue(){

//SynchronousQueue queue=new SynchronousQueue<>();

//LinkedBlockingDeque queue=new LinkedBlockingDeque<>();

ArrayBlockingQueue queue=new ArrayBlockingQueue(1);

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

queue);

poolExecutor.execute(new Runnable() {

@Override

public void run() {

System.out.print("任务1");

while (true){

}

}

});

poolExecutor.execute(new Runnable() {

@Override

public void run() {

System.out.print("任务2");

}

});

while (true){

}

}

这里用的ArrayBlockingQueue,传的capacity为1。如果任务1是个耗时的操作,那么任务2得不到执行。我们可以看一下ThreadPoolExecutor的源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27public void execute(Runnable command) {

if (command == null)

throw new NullPointerException();

int c = ctl.get();

//corePoolSize为0,这里不用看了,进不来

if (workerCountOf(c) < corePoolSize) {

if (addWorker(command, true))

return;

c = ctl.get();

}

//当任务1来了,添加到队列

//当任务2来了,任务1已经从队列出来了,所以可以添加到队列

if (isRunning(c) && workQueue.offer(command)) {

int recheck = ctl.get();

if (! isRunning(recheck) && remove(command))

reject(command);

//如果当前线程池线程空,则添加一个线程,所以任务1执行

//但是任务2来了,不满足这个判断条件,所以任务2得不到执行

else if (workerCountOf(recheck) == 0)

addWorker(null, false);

}

else if (!addWorker(command, false))

reject(command);

}

那么我再加一个任务3呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43public void testQueue(){

//SynchronousQueue queue=new SynchronousQueue<>();

//LinkedBlockingDeque queue=new LinkedBlockingDeque<>();

ArrayBlockingQueue queue=new ArrayBlockingQueue(1);

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

queue);

poolExecutor.execute(new Runnable() {

@Override

public void run() {

System.out.print("任务1");

while (true){

}

}

});

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

poolExecutor.execute(new Runnable() {

@Override

public void run() {

System.out.print("任务2");

}

});

poolExecutor.execute(new Runnable() {

@Override

public void run() {

System.out.print("任务3");

}

});

while (true){

}

}

这次可以执行了,不过得到的执行顺序为:任务1、任务3、任务2。为什么呢?因为当任务3进来了后添加不到队列了,而此时线程数量小于最大线程数,所以新建线程执行了任务3,当任务3执行完后会从队列里取任务2执行。

所以用ArrayBlockingQueue存在问题,哪怕把capacity改为别的数(除了0),也存在这样的问题。

那么LinkedBlockingDeque呢?LinkedBlockingDeque内部用的是链表结构,ArrayBlockingQueue用的是数组。LinkedBlockingDeque可以传capacity,也可以不传,不传的话有默认的为Integer.MAX_VALUE。它的效果其实是跟ArrayBlockingQueue一样的,也是有上述的问题。

而SynchronousQueue是一个没有容量的队列,往里面添加永远失败,会开一个线程去执行。(当然了是在线程数量小于最大线程数的情况下,不过这个应该可以保证啦)不会因为谁把谁堵住而得不到执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值