1.1 常识
-
进程:资源分配的基本单位
-
线程:调度执行的基本单位,多个线程共享一个线程资源
-
单核CPU设定多线程是否有意义?
-
线程数是不是设置的越大越好?
不是,切换线程也需要消耗资源。 -
工作线程数(线程池中线程数量)设多少合适?
- 根据CPU核数来设置线程(不充分,因为现实中并不会仅仅只运行我们的线程);
-
N
t
h
r
e
a
d
s
=
N
C
P
U
∗
U
C
P
U
∗
(
1
+
W
/
U
)
N_{threads}= N_{CPU} * U_{CPU} * (1 + W/U)
Nthreads=NCPU∗UCPU∗(1+W/U)
- 其中,最佳线程数=CPU核数 × CPU期望利用率 × [1+(I/O耗时(等待时间)/CPU耗时(运行时间))];
- 在工程上,线程的数量一般会设置为CPU核数+1,这样的话,当线程因为偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程可以顶上,从而保证CPU的利用率;
- 如何得知 W/U ?
- JProfiler(一种统计分析工具)
- 部署到实际服务器上进行测试
- …
1.2 创建线程的5种方法
- 继承Thread类
- 实现Runnable接口
- Lambda表达式
- ThreadPool
- Future Callable and FutureTask(可返回值)
note:
本质上只有一种方法:new Tread对象,调用run()方法。
1.3 线程状态
- NEW
- RUNNABLE
- TIMED WAITING
- WAITING
- BLOCKED
- TERMINATED
1.4 线程的“打断”
面试不怎么考
线程打断的三种方法:
- interrupt()
- 打断某个线程(设置标记位)
- isInterrupted()
- 查询线程是否被打断过(查询标志位)
- static interrupted()
- 查询当前线程(包括主线程)是否被打断过,并重置标志位
- 如何优雅结束一个线程?
Thead t = new Thread(() -> {
for(;;) {
if(Thread.currentThread().isInterrupted()) {
break;
}
}
})
Interrupt和sleep() wait() join():
- 可以通过Interrupt设置标志位,而后catch InterruptedException来进行处理。
Interrupt和锁:
- Interrupt不能打断正在竞争锁的线程:synchronized, lock
- Interrupt可以打断:lockInterruptibly
1.5 线程的“结束”
- 如何优雅地结束一个线程?
-
自然结束(尽量)
-
stop(): 太粗暴,无论线程处于什么状态,直接关闭,释放所有锁,不会做善后工作,容易造成数据不一致问题。
-
suspend() resume(): 暂停时不会释放锁,容易造成数据不一致问题。
-
使用 volatile 关键字
-
interrupt() and isInterrupted(比较优雅)
-
Thead t = new Thread(() -> {
while(! Thread.currentThread().isInterrupted()) {
// do something
}
});
t.start();
//do something
t.interrupt();
Note:
c. d. 都不适合要求精确时间,精确次数的场景,那么什么是合适的?
需要业务线程与外部线程相配合,需要用到锁。