线程
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()
--------------------------------------------------------------------------------------------------------
输出结果:
111
222
Thread
实现了 Runnable 接口。 下面看一下 Thread
实现的 run
方法:
//Thread.java
@Override
public void run() {
if (target != null) {
target.run();
}
}
这个 target 就是我们通过构造方法传入的自定义实现的 Runnable 对象。
ThreadFactory:
val threadFactory = object : ThreadFactory {
@Volatile
var count: Int = 0
override 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()
--------------------------------------------------------------------------------------------------------
输出结果:
1
2
3
4
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 线程--数值:0
thread1 线程--数值:1
thread1 线程--数值:2
thread1 线程--数值:3
thread1 线程--数值:4
thread1 线程--数值:5
main 线程--数值:0
main 线程--数值:1
main 线程--数值:2
main 线程--数值:3
main 线程--数值:4
main 线程--数值:5
如果这里不加 join,Thread1 和 main 线程可能交替打印数值,加了以后,main 线程就会等待 Thread1 执行完后,再进行执行。
线程结束后,可以再次 start 吗?
不可以。
//Thread.java
public 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-1
pool-1-thread-3
pool-1-thread-2
pool-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-1
pool-2-thread-3
pool-2-thread-4
pool-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.java
public 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 = true
thread1.start()
thread2.start()
thread3.start()
--------------------------------------------------------------------------------------------------------
输出结果:
111111
222222
这里等待了 3 秒后, thread3 没有输出 “333333”。