线程
Thread 和 Runnable:
//Runnable 测试val runnable =object :Runnable{override fun run() {println("111")}}val thread1 = Thread(runnable)thread1.start()//Thread 测试val thread2 = object : Thread() {override fun run() {super.run()println("222")}}thread2.start()--------------------------------------------------------------------------------------------------------输出结果:111222
Thread 实现了 Runnable 接口。 下面看一下 Thread 实现的 run 方法:
//Thread.java@Overridepublic void run() {if (target != null) {target.run();}}
这个 target 就是我们通过构造方法传入的自定义实现的 Runnable 对象。
ThreadFactory:
val threadFactory = object : ThreadFactory {@Volatilevar count: Int = 0override fun newThread(r: Runnable): Thread {count++return Thread(r, "$count")}}val runnable2 = object :Runnable{override fun run() {println(Thread.currentThread().name)}}threadFactory.newThread(runnable2).start()threadFactory.newThread(runnable2).start()threadFactory.newThread(runnable2).start()threadFactory.newThread(runnable2).start()--------------------------------------------------------------------------------------------------------输出结果:1234
Thread 常用的几个方法
currentThread():静态方法,返回对当前正在执行的线程对象的引用;start():开始执行线程的方法,java虚拟机会调用线程内的run()方法;yield():yield 在英语里有放弃的意思,同样,这里的yield()指的是当前线程愿意让出对当前处理器的占用。这里需要注意的是,就算当前线程调用了yield()方法,程序在调度的时候,也还有可能继续运行这个线程的;sleep():静态方法,使当前线程睡眠一段时间;join():使当前线程等待另一个线程执行完毕之后再继续执行,内部调用的是Object类的wait方法实现的;
join() 代码示例
val thread1 = object : Thread() {override fun run() {super.run()for (i in 0..5) {println("thread1 线程--数值:$i")}}}thread1.start()thread1.join()for (i in 0..5) {println("main 线程--数值:$i")}--------------------------------------------------------------------------------------------------------输出结果:thread1 线程--数值:0thread1 线程--数值:1thread1 线程--数值:2thread1 线程--数值:3thread1 线程--数值:4thread1 线程--数值:5main 线程--数值:0main 线程--数值:1main 线程--数值:2main 线程--数值:3main 线程--数值:4main 线程--数值:5
如果这里不加 join,Thread1 和 main 线程可能交替打印数值,加了以后,main 线程就会等待 Thread1 执行完后,再进行执行。
线程结束后,可以再次 start 吗?
不可以。
//Thread.javapublic synchronized void start() {if (started)throw new IllegalThreadStateException();group.add(this);started = false;try {nativeCreate(this, stackSize, daemon);started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}}
通过以上代码可以看出,started 为 true 的时候,会抛出异常。而在进行一次 start 后,就会把 started 置为 true。所以不能一个线程不能 start 两次。
Executor 和线程池
常用:newCachedThreadPool
创建无限多线程的线程池
val executors1 = Executors.newCachedThreadPool()val runnable = object : Runnable {override fun run() {println(Thread.currentThread().name)}}executors1.execute (runnable)executors1.execute (runnable)executors1.execute (runnable)executors1.execute (runnable)--------------------------------------------------------------------------------------------------------输出结果:pool-1-thread-1pool-1-thread-3pool-1-thread-2pool-1-thread-4
短时批量处理:newFixedThreadPool
创建固定大小的线程池。
val runnable = object : Runnable {override fun run() {println(Thread.currentThread().name)}}val executors2 = Executors.newFixedThreadPool(4)executors2.execute(runnable)executors2.execute(runnable)executors2.execute(runnable)executors2.execute(runnable)--------------------------------------------------------------------------------------------------------输出结果:pool-2-thread-1pool-2-thread-3pool-2-thread-4pool-2-thread-2
Callable 和 Future
val callable = object : Callable<String> {override fun call(): String {try {Thread.sleep(5000)} finally {}return "张三"}}val executors3: ExecutorService = Executors.newCachedThreadPool()val submit: Future<String> = executors3.submit(callable)try {val value: String = submit.get()println(value)} catch (e: Exception) {e.printStackTrace()}--------------------------------------------------------------------------------------------------------输出结果:(等待了 5 秒钟输出结果)张三
注意调用get方法会阻塞当前线程,直到得到结果。所以实际编码中建议使用可以设置超时时间的重载get方法。
下面是 Future 接口
public abstract interface Future<V> {public abstract boolean cancel(boolean paramBoolean);public abstract boolean isCancelled();public abstract boolean isDone();public abstract V get() throws InterruptedException, ExecutionException;public abstract V get(long paramLong, TimeUnit paramTimeUnit)throws InterruptedException, ExecutionException, TimeoutException;}
cancel方法是试图取消一个线程的执行。
注意是试图取消,并不一定能取消成功。因为任务可能已完成、已取消、或者一些其它因素不能取消,存在取消失败的可能。boolean类型的返回值是“是否取消成功”的意思。参数paramBoolean表示是否采用中断的方式取消线程执行。
所以有时候,为了让任务有能够取消的功能,就使用Callable来代替Runnable。如果为了可取消性而使用 Future但又不提供可用的结果,则可以声明 Future<?>形式类型、并返回 null作为底层任务的结果。
FutureTask
Future接口有一个实现类叫FutureTask。FutureTask是实现的RunnableFuture接口的,而RunnableFuture接口同时继承了Runnable接口和Future接口:
//RunnableFuture.javapublic interface RunnableFuture<V> extends Runnable, Future<V> {void run();}
那FutureTask类有什么用?为什么要有一个FutureTask类?前面说到了Future只是一个接口,而它里面的cancel,get,isDone等方法要自己实现起来都是非常复杂的。所以JDK提供了一个FutureTask类来供我们使用。
示例:
val callable = object : Callable<String> {override fun call(): String {try {Thread.sleep(5000)} finally {}return "张三"}}val executors4: ExecutorService = Executors.newCachedThreadPool()val futureTask: FutureTask<String> = FutureTask(callable)executors4.submit(futureTask)try {val value: String = futureTask.get()println(value)} catch (e: Exception) {e.printStackTrace()}--------------------------------------------------------------------------------------------------------输出结果:(等待了 5 秒钟输出结果)张三
和 Future 有所不同的是,Future 是从 submit 的返回值 Future 中获取返回值。FutureTask 是直接从 FutureTask 中获取返回值。
线程组和线程优先级
Java 中用 ThreadGroup 来表示线程组,我们可以使用线程组对线程进行批量控制。
每一个 Thread 必然存在于一个 ThreadGroup 中,Thread 不能独立于 ThreadGroup 存在。
线程组:ThreadGroup,可以统一限制线程组内线程优先级的最大值。创建一个线程组和线程的时候,不指定线程组,默认指定当前执行创建操作线程所在的线程组为自己的线程组。
fun main() {val thread = object : Thread() {override fun run() {super.run()println("当前线程的名称 111:${Thread.currentThread()}, hashCode 为:${Thread.currentThread().hashCode()}")println("当前线程的所在线程组的名称 111:${Thread.currentThread().threadGroup}, hashCode 为:${Thread.currentThread().threadGroup?.hashCode()}")}}thread.start()println("当前线程的名称 222:${Thread.currentThread()}, hashCode 为:${Thread.currentThread().hashCode()}")println("当前线程的所在线程组的名称 222:${Thread.currentThread().threadGroup}, hashCode 为:${Thread.currentThread().threadGroup?.hashCode()}")}--------------------------------------------------------------------------------------------------------输出结果:当前线程的名称 111:Thread[Thread-0,5,main], hashCode 为:2017079673当前线程的名称 222:Thread[main,5,main], hashCode 为:2016447921当前线程的所在线程组的名称 111:java.lang.ThreadGroup[name=main,maxpri=10], hashCode 为:666988784当前线程的所在线程组的名称 222:java.lang.ThreadGroup[name=main,maxpri=10], hashCode 为:666988784
线程组中有一个方法来控制线程组中线程的最大优先级 setMaxPriority(int pri) 。最大优先级默认为 10。
线程优先级
- 线程的优先级设定范围为 1-10。
- 优先级越大,首先执行的概率越高。只是越高而已,具体还要看操作系统的调度算法。
- 线程的默认优先级为 5。
- 线程的优先级默认不能超过所在的线程组的最大优先级。
守护线程
- 当前所有非守护线程结束后,守护线程也会结束。
- 通过Thread类的setDaemon(boolean on) 来设置是否为守护线程。
示例代码:
val thread1 = object : Thread() {override fun run() {super.run()Thread.sleep(1000)println("111111")}}val thread2 = object : Thread() {override fun run() {super.run()Thread.sleep(2000)println("222222")}}val thread3 = object : Thread() {override fun run() {super.run()Thread.sleep(3000)println("333333")}}thread3.isDaemon = truethread1.start()thread2.start()thread3.start()--------------------------------------------------------------------------------------------------------输出结果:111111222222
这里等待了 3 秒后, thread3 没有输出 “333333”。
