Java多线程

  • 介绍

在使用Java作为开发语言时,如果需要高效率、并行地处理请求,通常采用的方法就是“多线程”。

我们可以简单地认为多个线程是同时在运行的,这样效率自然就会很高,那是不是同时开启的线程越多,效率越高呢。不是这样的,因为所有这些线程都是需要一个调度中心来保证协调地工作的,就好比有时候“人多反而误事”。所以说,是不是要采用多线程,以及要同时开启多少个线程都是要根据实际需要来定的,不是越多越好。

那多少个线程数才是合适的呢,最笨也最好的办法就是通过测试结果来定。但是,由于多个线程是要争夺CPU资源来实现并行的,这样我建议可以使用CPU数量的两倍来定。

  • 最简单的线程使用

在Java中要实现一个线程,可以通过继承java.lang.Thread类或者是实现java.lang.Runnable接口。其中的run方法就是线程的实现逻辑,调用start方法来启动线程。

下面的例子是继承了Thread类:

下面的例子是实现了Runnable接口:

上述两种实现线程的方式都可以使用,但是由于Java规定类只能单继承,所以要使用继承Thread类的方式的话,就无法继承别的类了,这是他们的一个区别。

基本上只要使用了多线程,就会不可避免地要处理线程之间读写公共数据的安全性问题。使用线程间同步的方法是解决安全问题的一个手段。

使用关键字synchronized来实现同步,它可以加在方法或者代码块上。下面给出一个例子:

synchronized的实现原理是从软件层面依赖JVM。

  • 线程锁

这里说的线程锁指的是接口java.util.concurrent.locks.Lock,它的实现原理是从硬件层面依赖特殊的CPU指令。ReentrantLock是Lock接口的一个实现类。

另外,还有一个读写锁的接口java.util.concurrent.locks.ReadWriteLock。

java.util.concurrent.ExecutorService是JRE中提供的用于实现线程池的一个比较重要的接口。

下面是一个最简单的线程池的例子:

Executors.newCachedThreadPool()这种线程池维护0个核心线程数,最大线程数量为Integer.MAX_VALUE,线程的空闲失效时间为60秒。由此特性,可以想象到这种线程池适合于大量执行时间很短的任务。

Executors.newFixedThreadPool(int nThreads)

Executors.newSingleThreadExecutor()

Executors.newScheduledThreadPool(int corePoolSize)

除了JDK提供的线程池的实现以外,Spring也提供了相应的实现,详细内容请查阅《Spring线程池》。

对于JDK中提供的集合相关的线程安全性问题,请查阅《Java集合中的线程安全问题》。

发表评论

电子邮件地址不会被公开。 必填项已用*标注