文章目录

  • ​​生产者消费者-阻塞队列版本​​
  • ​​Callable接口​​

生产者消费者-阻塞队列版本

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_多线程


关于上面的代码,多线程环境下,调用资源类,关键变量要加volatile,原子类变量不用加,因为源码里面的包装类加了,我们在这里使用就不用加。如果是想做适配性很好的代码设计,要适配所有的阻塞队列的子类,就不能在方法里确定,而是要让调用者把具体的实现传进来,也就是面向接口的编程。所谓的高手都是传接口,绝对不是传类!

关于这里的代码,写,要足够的抽象,也就是传接口,要查,要利用反射,把具体的类的实现记一下日志。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_多线程_02


11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_阻塞队列_03


这个地方消费线程flag=false的行为,我不是很认同,消费线程取不到不应该停下吧,个人认为这个逻辑不对。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_子类_04


测试代码:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_阻塞队列_05


5s后叫停。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_多线程_06

执行结果:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_阻塞队列_07

总结一下阻塞队列版本的线程通信:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_子类_08

Callable接口

多线程的方式:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_子类_09


两者的区别:1.runable接口没有返回值。但另一个是有的(适用于带返回值的线程工作流)。2.接口实现方法不一样,一个run,一个call、3

那么callable接口怎么在项目中使用呢?如果只用thread去接收callable接口该如何处理呢?目前thread只能接受runable接口。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_多线程_10


如果一个类即实现了runable,也实现了callable,传这一个类就可以变相的适配了,这就是适配器模式的使用。

JDK给我们提供了,他就是futureTask接口。本身是runable接口的子类,传进去callable接口,就可以实现适配了。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_多线程_11


实际使用:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_子类_12


11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_阻塞队列_13


运行结果:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_子类_14


如何获得callable的返回值呢?api提供了,如下:

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_阻塞队列_15


这种用法在批次任务中,经常会出现。比如每一笔帐都要有返回值。

为什么callable会出现:并发,异步,导致callable出来了。

以前没有callable,编程的感觉就是一根签子通到底,冰糖葫芦串,顺序执行。如果节点占用时间过长,那就只能等着。

但是有了多线程之后,就可以用callable接口,把可以拆分的任务拆分出去并行执行,最后结果汇总。

多线程牛逼的不是锁,而是控制.

技巧:futureTask的get方法,建议放在最后执行。因为一旦get的那个任务还没执行完成,那么就会阻塞在这,所以get方法一般放在最后。

那么什么时候汇总呢?可以用自旋锁的思想,while一直去主动确认。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_子类_16

问题:如果一个futureTask被两个线程执行了2次,那么相关方法会如何执行?

结果是,只会执行一遍,因为一个计算过程算一遍就对了,不会算两遍。

11.互联网大厂高频面试题-阻塞队列(下)+callable介绍_阻塞队列_17


总结:多个线程抢一个futureTask只算一次。要想多算,要有多个futureTask。

以上就是我们第三种获得线程的方式。runable,callable,futureTask。