(一)初识Java线程 程序、进程、线程 Thread in

程序、进程、线程

程序

程序是「静态」的,存放在硬盘中的可执行文件,包括「代码指令」和「数据」

进程

进程是「运行中的程序」,是程序的一次启动和执行:操作系统从磁盘载入程序到内存,分配必要的资源,开始运行程序的指令

进程的组成:「代码段」,「数据段」,「PCB」(id,name,status,priority,物理地址,context,file,others)(描述信息,调度信息,资源信息,上下文)

线程

线程是“进程代码段”的一段「执行流程」

线程的组成:「PC」,「栈内存」(方法的调用和返回对应了栈帧的入栈和出栈),「线程基本信息」(id,name,status,priority,others)

进程和线程的区别

  • 一个进程至少有一个线程
  • 线程之间共享同一块地址空间(方法去内存,堆内存),打开的文件和其他资源,故上下文切换速度较快
  • 调度执行的基本单位:线程
  • 资源分配的基本单位:进程

Thread in Java

Thread

image.png

public void start()用来启动一个线程,当调用start()方法后,JVM才会开启一个新的线程来执行用户定义的线程代码逻辑,在这个过程中会为相应的线程分配需要的资源

public void run()是线程代码的逻辑入口,不是给用户程序来调用的,当调用start()方法之后,只要该线程获得了CPU时间片,就会执行run()方法

创建一个空线程

1
2
3
4
5
6
7
8
9
10
11
java复制代码public class Nov29 {
public static void main(String[] args) {
Thread emptyThread = new Thread("empty thread");
emptyThread.setPriority(5);
System.out.println("emptyThread.getId() = " + emptyThread.getId());
System.out.println("emptyThread.getName() = " + emptyThread.getName());
System.out.println("emptyThread.getPriority() = " + emptyThread.getPriority());
emptyThread.start();
System.out.println("end of emptyThread");
}
}

Thread类中,由于target对象为nullrun()方法什么也没做就结束了

1
2
3
4
5
6
typescript复制代码@Override
public void run() {
if (target != null) {
target.run();
}
}

继承Thread

  1. 继承Thread
  2. 重写run()方法
1
2
3
4
5
6
java复制代码public class FirstThread extends Thread{
@Override
public void run(){
System.out.println(" run() function in FirstThread ");
}
}
1
2
3
4
5
6
java复制代码public class Nov29 {
public static void main(String[] args) {
Thread firstThread = new FirstThread();
firstThread.start();
}
}

实现Runnable接口

  1. 定义一个类实现Runnable接口
  2. 实现run()方法
  3. 通过Thread类的构造方法public Thread(Runnable target)传入该类

函数式接口:有且仅有一个方法的接口

1
2
3
4
5
6
java复制代码public class SecondThread implements Runnable{
@Override
public void run() {
System.out.println(" run() in SecondThread ");
}
}
1
2
3
4
5
6
7
java复制代码public class Nov29 {
public static void main(String[] args) {
SecondThread secondThread = new SecondThread();
Thread thread = new Thread(secondThread);
thread.start();
}
}

对比:

  1. 通过继承Thread类来创建线程,可以直接使用Thread类的实例的方法
  2. 实现Runnable接口来创建线程则不能直接调用Thread类的实例的方法,需要通过Thread类的静态方法public Thread currentThread()来获取当前类
  3. 在实际开发中,由于Java不允许多继承,所以一般使用实现Runnable接口的方法来创建线程
  4. 通过实现Runnable接口的方法来创建线程能更好地实现数据和逻辑的分离
  5. Thread继承了Runnable接口,其中的run()方法无返回值,若需要异步获取程序的执行结构,应该采用实现Callable的方式

数据和逻辑的分离

todo:这个不太理解,之后需要细看

匿名内部类

1
2
3
4
5
6
7
8
9
10
11
java复制代码public class ThirdThread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("new a thread using anonymous inner class");
System.out.println("implement method in Runnable");
}
}).start();
}
}
1
2
3
4
5
6
7
8
9
10
11
java复制代码class ThirdThread {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
System.out.println("new a thread using anonymous inner class");
System.out.println("override method in Thread");
}
}.start();
}
}

Lambda表达式

一行代码搞定

1
2
3
4
5
java复制代码public class Nov29 {
public static void main(String[] args) {
new Thread(() -> System.out.println("new a thread using lambda")).start();
}
}

实现Callable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码public class FourthThread {
// 1. 新建Callable实现类
static class RunnableTask implements Callable<Long> {
// 2. 重写其中的call()方法,可以有返回值
@Override
public Long call() throws Exception {
Thread.sleep(3000);
return Long.MAX_VALUE;
}
}

public static void main(String[] args) throws ExecutionException, InterruptedException {
// 3. 使用FutureTask实例作为Thread构造器的target入参,构造新的Thread线程实例。
RunnableTask runnableTask = new RunnableTask();
FutureTask<Long> longFutureTask = new FutureTask<>(runnableTask);
Thread thread = new Thread(longFutureTask);
// 4. 调用Thread实例的start()方法启动新线程,启动新线程的run()方法并发执行
// 其内部的执行过程为:Thread实例的run(),FutureTask实例的run()方法,Callable实现类的call()方法
thread.start();
// 5. 调用FutureTask对象的get()方法阻塞性地获得并发线程的执行结果
System.out.println("longFutureTask.get() = " + longFutureTask.get());
}
}

使用线程池

不推荐使用 Executors 创建线程池

1
2
3
4
5
6
7
8
9
10
11
12
java复制代码public class ThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("无返回值execute()");
}
});
System.out.println("有返回值submit()" + pool.submit(new FourthThread.RunnableTask()).get());
}
}
  • execute() ,无返回值,参数只能是Runnable实现类,不能异步控制只能等其自动停止
  • submit() ,有返回值,参数可以是有返回值的Callable实现类,可以异步控制

Java线程原理

Java线程和操作系统线程

Java虚拟机把Java线程一对一映射到操作系统线程,线程的调度交给操作系统

在JVM看来,操作系统视角下的 running 状态和 ready 状态统一称为 runnable 状态

优先级

Java线程具有优先级,优先级高的获得调度机会统计规律上大于优先级低的线程,但不绝对

生命周期

image.png

1
2
3
4
5
6
7
8
java复制代码public enum State {
NEW,
RUNNABLE, // start()方法调用后,就是runnable状态,但并不一定立刻获得CPU时间片执行run()方法
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED; // 抛出异常或run()方法执行完
}

Java线程基本操作

操作

  • sleep:使线程休眠
  • yield:让出CPU时间片,让操作系统重新调度一次
  • interrupt:将线程状态设置为中断,不会像stop()方法那样中止一个线程,线程状态设置为中断后线程自己判断是继续执行还是终止
  • join:合并两个线程,让其中一个等待另一个执行完毕再执行;或者设置一个时间,时间到了就不等了
  • daemon:守护线程(为用户进程提供服务的进程,与用户进程的关系是和JVM线程的关系一个是主动一个是被动)

调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
sh复制代码➜  ~ jps
1217 Launcher
1218 ThreadSleep
1220 Jps
807
➜ ~ jstack 1218
2021-11-30 11:20:29
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.301-b09 mixed mode):

"Attach Listener" #12 daemon prio=9 os_prio=31 tid=0x00007fbfcc9fd800 nid=0x4503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #11 prio=5 os_prio=31 tid=0x00007fbfcc9fa000 nid=0x1003 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Thread-0" #10 prio=5 os_prio=31 tid=0x00007fbfca8eb800 nid=0x3c03 waiting on condition [0x000070000d21f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at ThreadSleep.lambda$main$0(ThreadSleep.java:5)
at ThreadSleep$$Lambda$1/1828972342.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)

"Service Thread" #9 daemon prio=9 os_prio=31 tid=0x00007fbfca86b800 nid=0x4703 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007fbfcc04b000 nid=0x4803 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007fbfcc8b5000 nid=0x3703 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007fbfcc04a000 nid=0x3503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007fbfca85a000 nid=0x4903 runnable [0x000070000cc0d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x0000000795713788> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x0000000795713788> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:49)

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fbfcc049000 nid=0x4a03 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fbfca81c800 nid=0x5103 in Object.wait() [0x000070000c901000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000795588ee0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x0000000795588ee0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007fbfcb01b000 nid=0x5203 in Object.wait() [0x000070000c7fe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000795586c00> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x0000000795586c00> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=31 tid=0x00007fbfca817800 nid=0x2b03 runnable

"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007fbfcc00a000 nid=0x2407 runnable

"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007fbfcc80e800 nid=0x2003 runnable

"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007fbfca80e000 nid=0x2203 runnable

"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007fbfcc80f000 nid=0x2a03 runnable

"VM Periodic Task Thread" os_prio=31 tid=0x00007fbfcc04e000 nid=0x3b03 waiting on condition

JNI global references: 319

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%