java多线程使用场景有哪些?有何作用?

2020-05-05 15:05:38 java常见问答 9016

我们都知道在java软件开发领域,多线程这一关键词从来就不会缺席,那么你知道java多线程的使用场景有哪些吗?都用来做什么呢?

Thread。第一类就是Thread类了。大家都知道有线程有两种实现方式。第一可以继承Thread覆盖它的run方法;第二种是实现Runnable接口,实现它的run方法;而第三种创建线程的方法,就是通过线程池。那么具体代码实现,就放在run方法中。

一般会关注两种情况。一个是线程退出的条件,一个就是异常处理情况。

线程退出。有的run方法执行完成之后,线程就会退出了。但有的run方法是永远不会结束的。结束一个线程肯定不是通过Thread.stop()方法的,这个方法早已经在java1.2版本就被废弃了。所以大体会有两种方式控制线程。

定义退出标志放在while中

代码一般是这样的。

private volatile boolean flag = true;
public void run()
{
    while (flag)
    {}
}

标志呢一般使用volatile进行修饰,使其可读,然后再通过设置这个值来控制线程的运行,这就已经成了约定俗成的套路。

使用interrupt方法终止线程。类似下面这种。

while(!isInterrupted()){……}

对于InterruptedException,比如Thread.sleep所抛出的,我们一般是去补获它,然后再静悄悄的忽略掉。中断允许一个可取消任务来清理正在进行的工作,然后通知其他任务它要被取消,最后才终止,在这种情况下,该类异常需要被仔细处理。

interrupt方法是不一定会真正”中断”线程的,它只是一种协作机制。interrupt方法通常不能中断一些处于阻塞状态的I/O操作。比如写文件,或者socket传输等。这种情况,需要同时调用正在阻塞操作的close方法,才能够正常的退出。

interrupt系列使用时候一定要注意,会引入bug,甚至死锁。

异常处理。一般java中会抛出两种异常。一种是必须要捕获的,比如InterruptedException,否则无法通过编译;另外一种是可以处理也可以不处理的,比如NullPointerException等等。

那么在我们的任务运行中,很有可能抛出这两种异常。对于第一种异常,是必须放在try,catch中的。但第二种异常如果不去处理的话,是会影响任务的正常运行的。

有很多时候在处理循环的任务时,没有捕获一些隐式的异常,造成任务在遇到异常的情况下,并不能继续执行下去。如果不能确定异常的种类,可以直接捕获Exception或者更通用的Throwable。

while (!isInterrupted())
{
    try
    {
        ……}
    catch (Exception ex)
    {
        ……}
}

同步方式。java中实现同步的方式有很多,大体分为以下几种。

synchronized 关键字,wait、notify等,Concurrent包中的ReentrantLock,volatile关键字,ThreadLocal局部变量。

生产者、消费者是wait、notify最典型的应用场景,这些函数的调用,是必须要放在synchronized代码块里才能够正常运行的。

信号量。Semaphore虽然有一些应用场景,但大部分属于炫技的,在编码中应该尽量少用。

信号量可以实现限流的功能,但它只是常用限流方式的一种。其他两种是漏桶算法、令牌桶算法。

hystrix的熔断功能,也有使用信号量进行资源的控制。

End。不管是wait、notify,还是同步关键字或者锁,能不用就不要用,毕竟它们会引发程序的复杂性。最好的方式就是,是直接使用concurrent包所提供的机制,来规避一些编码方面的问题。

concurrent包中的CAS概念,在一定程度上算是无锁的一种实现。更专业的有类似disruptor的无锁队列框架,但它依然是建立在CAS的编程模型上的。近些年,类似AKKA这样的事件驱动模型正在走红,但编程模型简单,不代表实现简单,背后的工作依然需要多线程去协调。

golang引入协程(coroutine)概念以后,对多线程加入了更加轻量级的补充。java中可以通过javaagent技术加载quasar补充一些功能,但我觉得你不会为了这丁点效率去牺牲编码的可读性。

那么以上就是有关java多线程的所有内容了,还想了解更多java架构师的相关信息,记得马上来关注本站消息哦。