目录
目录
线程生命周期
- 初始: new一个线程, 还没执行start方法
- 运行: 运行start方法后, 又分为就绪和运行中两种状态
- 就绪: 运行start方法后, 会进入线程队列, 等待系统调度, 分配时间片
- 运行中: 分配到CPU时间片, 开始真正执行任务代码
- 等待: 调用wait,join,park方法进入等待, 调用特定方法才会唤醒
- 超时等待: 和等待不同, 一定时间后会自动唤醒
- 阻塞: 未获取到synchronized锁, 进入到阻塞状态
- 结束: 异步任务run方法执行完, 线程生命周期结束
线程优先级
在java里面, 可以通过Thread.setPriority(int)设置优先级, 范围1-10.优先级高的线程会优先分配CPU时间片, 但是不同操作系统里面, 优先级范围可能是1-100, 不好转换, 所以有些系统会自动忽略设置的优先级.
休眠或者频繁IO操作的线程可以设置高优先级, 执行时间久或者偏运算占用CPU高的建议设置低优先级, 防止CPU被独占.
线程调度
- 协调式线程调度: 运行时间是由线程自己控制, 线程执行完通知其他线程执行.缺点是如果线程出了问题, 程序会一直阻塞
- 抢占式系统调度: 由系统分配CPU时间片, 执行时间和顺序不可控.只能设置优先级或者yeild勉强控制, 在ready状态下, 优先级越高越容易执行, yeild可以让出CPU时间片, 可能让给其他线程优先执行. java使用抢占式系统调度.
协程
操作系统线程和应用线程关系
- 内核线程(1:1)
- 用户线程(1:N)
- 用户线程加轻量级混合进程(N:M)
JDK早期(1.2以前)是由用户线程(1:N)实现, JDK1.3后使用内核线程方式(1:1), 因为和操作系统线程一对一, 交由操作系统调度不可控, 所以是抢占式系统调度
因为大多数用户线程是协同式系统调度, 所以用户线程也被叫做协程.
协程优势是更轻量, 正常一个内核线程栈容量是1兆, 而协程只要几百字节到几KB;在java里面,线程池容量顶多几百, 而在支持协程的应用, 支持存在的线程可以到十万.
协程适合高并发的场景, 不适合大量计算.协程提供的是规模, 而不是速度.
纤程-java实现的协程
目前Java中比较出名的协程库是Quasar[ˈkweɪzɑː(r)](Loom项目的Leader就是Quasar的作者Ron Pressler), Quasar的实现原理是字节码注入,在字节码层面对当前被调用函数中的所有局部变量进行保存和恢复。这种不依赖Java虚拟机的现场保护, 虽然能够工作,但影响性能。
使用:
- 启动VM命令加上-javaagent:D:\repository\co\paralleluniverse\quasar-core\0.7.9\quasar-core-0.7.9.jar
- 引用maven
<dependency>
<groupId>co.paralleluniverse</groupId>
<artifactId>quasar-core</artifactId>
<version>0.7.9</version>
</dependency>
代码示例:
package org.example;
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.Strand;
import com.google.common.base.Stopwatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class Main {
private static CountDownLatch countDownLatch = new CountDownLatch(10000);
private static ExecutorService executorService = Executors.newCachedThreadPool();
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
testQuasar();
// testThread();
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("Hello world! 耗时" + (end - start));
executorService.shutdown();
}
private static void testQuasar() {
IntStream.range(0, 10000).forEach(i -> new Fiber() {
@Override
protected Object run() throws SuspendExecution, InterruptedException {
Strand.sleep(1000);
countDownLatch.countDown();
return "";
}
}.start());
}
private static void testThread() {
IntStream.range(0, 10000).forEach(i -> executorService.submit(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
countDownLatch.countDown();
}));
}
}
协程耗时:
线程耗时:
守护线程
守护线程是一种支持型线程, 主要负责后台调度和支持工作, 一旦主线程结束, 守护线程也会结束.通过Thread.setDaemon(true)设置守护线程