用了线程之后,我们会直接创造线程吗?
答案是,会。毕竟线程模型简单易用。那线程的回收问题咋办?咋办,低并发情况下有垃圾回收,你就随便用呗。大部分人实际上不会去写多线程。写多线程的人实际上也不一定用线程池。作为程序员,首先要体验编程的快乐才行。然后碰到问题了再来考虑复杂用法。基于用法去了解概念,而不是基于概念去找场景。
现在碰到高并发场景了,对应用资源的使用要开始细扣了。于是不能再随意创建Thread,因为每次创建都有一系列步骤,比如开内存空间,初始化啥啥的。少了无所谓,多了就耗时了。
另一个问题是创建之后,还得销毁。
还有一个问题是创建了之后,线程要做的事儿也没做完,有事儿卡出了,所以也不能销毁。那就会内存溢出了。
所以,我们首先要盘业务逻辑。业务逻辑理解透彻之后,我们就把线程想象成人,人会不会打架,人会不会卡住。毕竟所有程序都是在翻译人能做的事而已,机器学习也不例外。
盘业务逻辑是业务逻辑的事。虽然重要但没法讲。所以就再来看技术上的事。如何对线程这种稀缺资源进行复用。答案就是,池,pool。要用了去池里拿,用完了放回池子里。
那线程池要有什么行为呢?能创建线程,能指定线程跑起来。
线程池要有什么属性呢?线程池大小。
这样的线程池是不是能覆盖所有场景呢?其实还不够,就是如果比预料的多的线程来了咋办。那就搞一个队列,把多的线程放进去。放进去,但是不给跑。
从业务上想想线程池该有的行为,也就了解了它该有哪些参数了。
Runnable和Callable的差别。
首先,还是碰到了问题。Runnable只管执行,不好传参。如果要传参,就要使用更高的上下文的共享变量,这变得可难看了。
所以Callable就是来解决传参问题的。
通过EecutorService执行完Callable后,就会产生一个Future对象,我们就可以通过Future去调用Callable的执行结果了。
还有个问题,用Future的必然是调用方,Callable又是那个被调用的,两个分属两个线程。那前者调用后者的时候,后者如果没执行完咋办。这是线程之间合作经常碰到的问题。就是等着。等着,就说明调用方线程阻塞了。
调用者等着,就说明这是一个同步的机制。所以Future也是一个同步阻塞的范式。
使用多线程往往意味着异步,但就像很多人一块干活一样,就算任务拆的稀碎,最后总要收口。那这种收口有啥好办法不。后面会讲CountDownLatch和CyclicBarrier。
网友评论