『深入学习Java』(三) Java 线程基础
什么是线程
进程:通俗讲就是正在运行的程序,会占用系统资源。 线程:属于进程,是进程中独立的执行路径。 为什么要使用多线程?在项目有很多功能需要同时运行的时候,可以提高效率。
- 并行与并发
并行(concurrent)
与并发(parallel)
,不是同一个概念。 并发是同一时间应对多件事情的能力;而并行是同一时间做多件事情的能力。 例子:你在家蹲坑,公司领导来电话了,让你处理个文件。- 并发。 你给领导电话挂了,过了一会儿,你蹲完了,再打电话问领导啥事儿啊。随后你去房间拿出了笔记本开始处理文件。
- 并行。 "好的,领导。我现在就处理。"随后你从旁边掏出了笔记本,开始一边蹲坑,一边处理文件。
所以,这里的重点就是,是否在同一时间能够做多件事。
Java 中创建线程方式
实现 Thread 的 run 方法
public void test01() {
Thread thread = new Thread(){
@Override
public void run() {
log.warn("线程运行...");
}
};
thread.start();
}
Runable 配合 Thread
public void test02() {
Runnable runnable = () -> log.warn("线程运行...");
Thread thread = new Thread(runnable);
thread.start();
}
Callable 配合 Thread
Callable 可实现获取线程的返回值。 这里需要注意 Callable 需要被 FutureTask 封装。
public void test03() throws ExecutionException, InterruptedException {
Callable<String> callable = () -> "有返回值的线程...";
FutureTask<String> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
String o = futureTask.get();
log.info(o);
}
线程常见方法
方法名称 | 方法描述 | 备注 |
---|---|---|
start() | 启动一个新线程。 | 线程进入就绪状态,CPU时间片分配到时,可立即执行 |
run() | 线程启动后,要执行的方法体 | - |
join() | 等待线程结束 | - |
setPriority() | 设置线程优先级 | 1-10 之间,提高线程被调度的概率 |
interrupt() | 中断线程 | 线程调用wait() 、join() 、 sleep() ,抛出 InterruptedException 并且清除中断标记。 |
interrupted() | 线程是否被中断,清除线程的中断状态 | - |
isInterrupted() | 线程是否被中断,不清除中断状态 | - |
sleep() | 线程休眠n毫秒 | - |
yield() | 向调度程序提示当前线程愿意放弃其当前对处理器的使用 | - |
getState() | 获取线程状态。 | Java 中线程有六种状态。NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED |
线程状态
NEW
尚未启动的线程。RUNNABLE
可运行线程,正在 Java 虚拟机中执行。 但它可能正在等待来自操作系统的其他资源,例如处理器,即CPU时间片调度。BLOCKED
线程阻塞,等待监视器锁。 正等待Monitor Lock
进入同步代码块/方法 或 在调用Object.wait
后重新进入同步代码块/方法。WAITING
等待线程的线程状态。- 调用以下方法,使线程处于等待状态:
Object.wait
Thread.join
LockSupport.park
- 例如
- 一个对对象调用
Object.wait()
的线程正在等待另一个线程对该对象调用Object.notify()
或Object.notifyAll()
。 - 已调用
Thread.join()
的线程正在等待指定线程终止
- 一个对对象调用
- 调用以下方法,使线程处于等待状态:
TIMED_WAITING
具有指定等待时间的等待状态。 调用以下方法之一,线程处于定时等待状态:Thread.sleep(long)
Object.wait(long)
Thread.join(long)
LockSupport.parkNanos
LockSupport.parkUntil
TERMINATED
已终止线程的线程状态。线程已完成执行
线程流转图
左侧的 NEW
、RUNNABLE
、TERMINATED
,是一个正常运行的线程的生命流程。即从创建到新增,再到死亡。
BLOCKED
、WAITING
、TIME_WAITING
则是线程处于挂起状态
,但是这几个状态的具体含义是有区别的。
BLOCKED
竞争阻塞状态。例如Thread1
、Thread2
同时竞争锁A,Thread1
竞争得了锁A,则此时Thread2
处于BLOCKED
状态,等待Thread1
释放锁,再次竞争。WAITING
没有时间限制的等待状态,即不唤醒会一直处于等待态。TIME_WAITING
具有等待时间的等待状态。即时间一到,就会自己又运行的。 下面是一段状态流转的示例代码
public void runnableTo1() throws InterruptedException {
Object o = new Object();
Thread thread1 = new Thread(() -> {
synchronized (o) {
log.info("线程运行。");
try {
o.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("另外的代码。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("结束。");
}
});
thread1.start();
Thread thread2 = new Thread(() -> {
synchronized (o) {
log.info("线程运行。");
try {
o.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("另外的代码。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("结束。");
}
});
thread2.start();
Thread.sleep(500);
Thread.State state = thread1.getState();
System.out.println("thread1:"+state);
Thread.State state2 = thread2.getState();
System.out.println("thread2:"+state2);
synchronized (o) {
o.notifyAll();
}
System.out.println("thread1:"+thread1.getState());
System.out.println("thread2:"+thread2.getState());
Thread.sleep(1100);
System.out.println("thread1:"+thread1.getState());
System.out.println("thread2:"+thread2.getState());
Thread.sleep(1000);
System.out.println("thread1:"+thread1.getState());
System.out.println("thread2:"+thread2.getState());
}
运行结果
[Thread-1] INFO ThreadStatusTest - 线程运行。
[Thread-2] INFO ThreadStatusTest - 线程运行。 // 到这里,两个线程都开始运行了。
thread1:WAITING
thread2:WAITING // 到这里,线程里调用了 wait() 方法,所以线程处于 `WAITING` 状态。
thread1:BLOCKED // o.notifyAll() 之后,thread1 未竞争到锁,所以处于`BLOCKED`
thread2:RUNNABLE // o.notifyAll() 之后,thread2 竞争到锁,所以处于`RUNNABLE`
[Thread-2] INFO ThreadStatusTest - 另外的代码。
[Thread-2] INFO ThreadStatusTest - 结束。
[Thread-1] INFO ThreadStatusTest - 另外的代码。
thread1:TIMED_WAITING // Thread.sleep(1000) 之后,线程就处于`TIMED_WAITING`
thread2:TERMINATED // thread2 执行结束了,处于最终结束态。
15:54:21.364 [Thread-1] INFO ThreadStatusTest - 结束。
thread1:TERMINATED
thread2:TERMINATED