Category |
Methods Signature |
Introduction |
Creation of thread |
Thread() |
|
Thread(String name) |
|
Thread(Runnable target) |
|
Thread(Runnable target,String name) |
|
Thread method |
void start()
|
Start thread |
##static void sleep(long millis)
|
Thread sleep
|
static void sleep(long millis,int nanos)
|
void join()
|
Make other threads wait for the current thread to terminate
|
void join( long millis)
|
void join(long millis,int nanos)
|
##static void yield() | The currently running thread releases processor resources |
Gets thread reference | static Thread currentThread() | Returns the currently running thread reference |
When the two threads are not doing any processing, they will run alternately.
When using the boolean type to control the loop of a thread, add the volatile keyword before the variable. Volatile ensures that the thread can correctly read the values written by other threads.
Note:
The function of the sleep() method: makes the thread sleep for the specified time.
The function of the join() method: //Make other threads wait for the current thread to complete execution.
Multi-threading case
Example 1:
1 package com.czgo;
2
3
4
5 /**
6
7 * 线程先生
8
9 * @author 疯子
10
11 *
12
13 */
14
15 public class Actor extends Thread {
16
17 @Override
18
19 public void run() {
20
21 //getName():获取当前线程的名称
22
23 System.out.println(getName()+"是一个演员!");
24
25 //用来记录线程跑的次数
26
27 int count = 0;
28
29 boolean keepRunning = true;
30
31 while(keepRunning){
32
33 System.out.println(getName()+"登台演出"+(++count));
34
35 if(count==100){
36
37 keepRunning = false;
38
39 }
40
41 if(count%10==0){
42
43 try {
44
45 Thread.sleep(1000);
46
47 } catch (InterruptedException e) {
48
49 e.printStackTrace();
50
51 }
52
53 }
54
55 }
56
57 System.out.println(getName()+"的演出结束了!");
58
59 }
60
61
62
63 public static void main(String[] args) {
64
65 Thread actor = new Actor();
66
67 //setName:设置线程的名称
68
69 actor.setName("Mr.Thread");
70
71 //启动线程
72
73 actor.start();
74
75
76
77 Thread actressThread = new Thread(new Actress(),"Ms.Runnable");
78
79 actressThread.start();
80
81 }
82
83 }
84
85
86
87 class Actress implements Runnable{
88
89 @Override
90
91 public void run() {
92
93 //getName():获取当前线程的名称
94
95 //currentThread()获取当前线程的引用
96
97 System.out.println(Thread.currentThread().getName()+"是一个演员!");
98
99 //用来记录线程跑的次数
100
101 int count = 0;
102
103 boolean keepRunning = true;
104
105 while(keepRunning){
106
107 System.out.println(Thread.currentThread().getName()+"登台演出"+(++count));
108
109 if(count==100){
110
111 keepRunning = false;
112
113 }
114
115 if(count%10==0){
116
117 try {
118
119 Thread.sleep(1000);
120
121 } catch (InterruptedException e) {
122
123 e.printStackTrace();
124
125 }
126
127 }
128
129 }
130
131 System.out.println(Thread.currentThread().getName()+"的演出结束了!");
132
133 }134 135 }
Copy after login
Example 2:
Army:
1 package com.czgo;
2
3
4
5 /**
6
7 * 军队线程
8
9 * 模拟作战双方的行为
10
11 * @author 疯子
12
13 *
14
15 */
16
17 public class ArmyRunnable implements Runnable {
18
19
20
21 //volatile保证了线程可以正确的读取其他线程写入的值
22
23 //可见性 ref JMM,happens-before
24
25 volatile boolean keepRunning = true;
26
27
28
29 @Override
30
31 public void run() {
32
33
34
35 while(keepRunning){
36
37 //发动5连击
38
39 for(int i=0;i<5;i++){
40
41 System.out.println(Thread.currentThread().getName()+"进攻对方["+i+"]");
42
43 //让出了处理器时间,下次谁进攻还不一定呢!
44
45 Thread.yield();
46
47 }
48
49 }
50
51
52
53 System.out.println(Thread.currentThread().getName()+"结束了战斗!");
54
55
56
57 }
58
59 }
Copy after login
Key Character:
1 package com.czgo;
2
3
4
5 /**
6
7 * 关键人物
8
9 * @author 疯子
10
11 *
12
13 */
14
15 public class KeyPersonThread extends Thread {
16
17 @Override
18
19 public void run() {
20
21 System.out.println(Thread.currentThread().getName()+"开始了战斗!");
22
23 for(int i=0;i<10;i++){
24
25 System.out.println(Thread.currentThread().getName()+"左突右杀,攻击随军...");
26
27 }
28
29 System.out.println(Thread.currentThread().getName()+"结束了战斗!");
30
31
32
33 }
34
35 }
Copy after login
Stage:
1 package com.czgo;
2
3
4
5 /**
6
7 * 隋唐演义大戏舞台
8
9 * @author win7
10
11 *
12
13 */
14
15 public class Stage extends Thread {
16
17
18
19 @Override
20
21 public void run() {
22
23 System.out.println("欢迎观看隋唐演义");
24
25
26
27 try {
28
29 Thread.sleep(5000);
30
31 } catch (InterruptedException e2) {
32
33 e2.printStackTrace();
34
35 }
36
37
38
39 System.out.println("大幕徐徐拉开");
40
41
42
43 try {
44
45 Thread.sleep(5000);
46
47 } catch (InterruptedException e2) {
48
49 e2.printStackTrace();
50
51 }
52
53
54
55 System.out.println("话说隋朝末年,隋军与农民起义军杀得昏天暗地...");
56
57
58
59 //隋朝军队
60
61 ArmyRunnable armyTaskOfSuiDynasty = new ArmyRunnable();
62
63 //农民起义军
64
65 ArmyRunnable armyTaskOfRevolt = new ArmyRunnable();
66
67
68
69 //使用Runnable接口创建线程
70
71 Thread armyOfSuiDynasty = new Thread(armyTaskOfSuiDynasty,"隋军");
72
73 Thread armyOfSuiRevolt = new Thread(armyTaskOfRevolt,"农民起义军");
74
75
76
77 //启动线程,让军队开始作战
78
79 armyOfSuiDynasty.start();
80
81 armyOfSuiRevolt.start();
82
83
84
85 //舞台线程休眠,大家专心观看军队的厮杀
86
87 try {
88
89 //Thread会指向当前类的线程
90
91 Thread.sleep(50);
92
93 } catch (InterruptedException e) {
94
95 e.printStackTrace();
96
97 }
98
99 System.out.println("正当双方激战正酣,半路杀出了个程咬金");
100
101
102
103 Thread mrCheng = new KeyPersonThread();
104
105 mrCheng.setName("程咬金");
106
107
108
109 System.out.println("程咬金的理想就是结束战争,使百姓安居乐业!");
110
111
112
113 //停止军队作战
114
115 //停止线程的方法
116
117 armyTaskOfSuiDynasty.keepRunning=false;
118
119 armyTaskOfRevolt.keepRunning=false;
120
121
122
123 try {
124
125 Thread.sleep(2000);
126
127 } catch (InterruptedException e1) {
128
129 e1.printStackTrace();
130
131 }
132
133 134 135 //历史大戏留给关键人物
136
137 mrCheng.start();
138
139
140
141 try {
142
143 //使其他线程等待当前线程执行完毕
144
145 mrCheng.join();
146
147 } catch (InterruptedException e) {
148
149 e.printStackTrace();150 151 }
152
153
154
155 System.out.println("战争结束,人民安居乐业,程先生实现了积极的人生梦想,为人民作出了贡献!");
156
157 System.out.println("谢谢观看隋唐演义,再见!");
158
159 }
160
161
162
163 public static void main(String[] args) {
164
165 new Stage().start();
166
167 }
168
169 }
Copy after login
Correct stopping of threads
How to correctly stop threads in Java:
Yes Control the exit of the loop through boolean type.
not stop method
The stop() method will stop the thread abruptly.
The stop() method is the wrong way to stop a thread.
Interaction of threads
Race Condition
When multiple threads share access to the same data (memory area) at the same time ), each thread attempts to operate on the data, causing the data to be corrupted. This phenomenon is called a race condition.
What is mutual exclusion?
How is mutual exclusion achieved?
Can only be accessed by one thread, mutually exclusive.
Mutual exclusion implementation: synchronized (intrinsic lock) lock.
Synchronization implementation: wait()/notify()/notifyAll().
How to expand your knowledge of Java concurrency
Java Memory Mode
JMM describes how Java threads interact through memory
Happens -before
Synchronized, volatile&final
Locks&Condition
High-level implementation of Java lock mechanism and wait conditions
. ##Thread Safety
Atomicity and Visibility Thread-programming interactive model
# Producer-Consumer Model
Read-Write Lock Model
FUTURE Model
## Worker Thread Model Java5 complicate programming tools java.util.concurrent thread pool ExecutorService Sering & FUTURE ## BLOCKINGQUEUE
## steam: Recommend two books: Core JavaJava concurrency in practiceComparison of two methods of thread creation
Thread:① Inherit the Thread class; Runnable: ① The Runnable method can avoid the defects of the Thread method due to the single inheritance feature of Java. ② Runnable code can be shared by multiple threads (Thread instances), which is suitable for situations where multiple threads process the same resource. Case: Thread: 1 package com.czgo;
2
3
4
5 class MyThread extends Thread{
6
7
8
9 private int ticketsCont = 5; //一共有5张火车票
10
11
12
13 private String name; //窗口,也即是线程的名字
14
15
16
17 public MyThread(String name){
18
19 this.name = name;
20
21 }
22
23 24 25 @Override
26
27 public void run() {
28
29 30 31 while(ticketsCont>0){
32
33 ticketsCont--; //如果还有票,就卖掉一张
34
35 System.out.println(name+"卖了1张票,剩余票数为:"+ticketsCont);
36
37 }
38
39 }
40
41
42
43 }
44
45
46
47 public class TicketsThread {
48
49
50
51 public static void main(String[] args) {
52
53 //创建3个线程,模拟三个窗口卖票
54
55 MyThread mt1 = new MyThread("窗口1");
56
57 MyThread mt2 = new MyThread("窗口2");
58
59 MyThread mt3 = new MyThread("窗口3");
60
61 62 63 //启动这三个线程,也即是窗口,开始卖票
64
65 mt1.start();
66
67 mt2.start();
68
69 mt3.start();
70
71
72
73 }
74
75
76
77 }
Copy after login
Runnable: 1 package com.czgo;
2
3
4
5 class MyThread implements Runnable{
6
7
8
9 private int ticketsCont = 5; //一共有5张火车票
10
11
12
13 @Override
14
15 public void run() {
16
17
18
19 while(ticketsCont>0){
20
21 ticketsCont--; //如果还有票,就卖掉一张
22
23 System.out.println(Thread.currentThread().getName()+"卖了1张票,剩余票数为:"+ticketsCont);
24
25 }
26
27
28
29 }
30
31
32
33 }
34
35
36
37 public class TicketsRunnable {
38
39
40
41 public static void main(String[] args) {
42
43
44
45 MyThread mt1 = new MyThread();
46
47 MyThread mt2 = new MyThread();
48
49 MyThread mt3 = new MyThread();
50
51
52
53 //创建三个线程来模拟三个售票窗口
54
55 Thread th1 = new Thread(mt1,"窗口1");
56
57 Thread th2 = new Thread(mt2,"窗口2");
58
59 Thread th3 = new Thread(mt3,"窗口3");
60
61
62
63 //启动这三个线程,也即是三个窗口开始卖票
64
65 th1.start();
66
67 th2.start();
68
69 th3.start();
70
71
72
73 }
74
75
76
77 }
Copy after login
Life cycle of thread
Illustration : Create: Create a new thread object, such as Thread thd = new Thread().
Ready: After creating the thread object, the thread's start() method is called (note: at this time, the thread just enters the thread queue, waiting to obtain cpu service, and has the conditions to run, but it does not necessarily have started running).
Run: Once the thread in the ready state obtains the CPU resource, it enters the running state and starts executing the logic in the run() method.
Termination: After the thread's run() method is executed, or the thread calls the stop() method, the thread enters the terminated state. Blocking: Under certain circumstances, an executing thread temporarily gives up CPU resources for some reason, suspends its own execution, and enters a blocking state, such as calling the sleep() method. .
The patron saint of threads-Guardian thread
There are two types of Java threads:
User Thread: runs in the foreground and performs specific tasks. For example, the main thread of the program, the sub-threads connected to the network, etc. are all user threads. Daemon thread: runs in the background and serves other foreground threads. Features: Once all user threads have finished running, the daemon thread will end its work together with the JVM.
Application: Monitoring thread in the database connection pool, monitoring thread after the JVM virtual machine is started. The most common daemon thread: garbage collection thread. 如何设置守护线程
可以通过调用Thread类的setDaemon(true)方法来设置当前线程为守护线程。
注意事项:
setDaemon(true)必须在start()方法之前调用,否则会抛出IllegalThreadStateException异常。
在守护线程中产生的新线程也是守护线程
不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑。
案例:
1 package com.czgo;
2
3
4
5 import java.io.File;
6
7 import java.io.FileOutputStream;
8
9 import java.io.IOException;
10
11 import java.io.OutputStream;
12
13 import java.util.Scanner;
14
15
16
17 class DaemonThread implements Runnable{
18
19 @Override
20
21 public void run() {
22
23 System.out.println("进入守护线程"+Thread.currentThread().getName());
24
25 try {
26
27 writeToFile();
28
29 } catch (IOException e) {
30
31 e.printStackTrace();
32
33 } catch (InterruptedException e) { 34 35 e.printStackTrace();
36
37 }
38
39 System.out.println("退出守护线程"+Thread.currentThread().getName());
40
41
42
43 }
44
45
46
47 private void writeToFile() throws IOException, InterruptedException{
48
49 File filename = new File("C:\\ide"+File.separator+"daemon.txt");
50
51 OutputStream os = new FileOutputStream(filename,true);
52
53 int count = 0;
54
55 while(count<999){
56
57 os.write(("\r\nword"+count).getBytes());
58
59 System.out.println("守护线程"+Thread.currentThread().getName()+"向文件中写入了word"+count++);
60
61 Thread.sleep(1000);
62
63 }
64
65 os.close();
66
67 }
68
69 }
70
71
72
73 public class DaemonThreadDemo {
74
75
76
77 public static void main(String[] args) {
78
79
80
81 System.out.println("进入主线程"+Thread.currentThread().getName());
82
83 DaemonThread daemonThread = new DaemonThread();
84
85 Thread thread = new Thread(daemonThread);
86
87 thread.setDaemon(true);
88
89 thread.start();
90
91
92
93 Scanner sc = new Scanner(System.in);
94
95 sc.next();
96
97
98
99 System.out.println("退出主线程"+Thread.currentThread().getName());
100
101 }
102
103
104
105 }
Copy after login
使用jstack生成线程快照
jstack
作用:生成jvm当前时刻线程的快照(threaddump,即当前进程中所有线程的信息)
目的:帮助定位程序问题出现的原因,如长时间停顿、cpu占用率过高等。
如何使用jstack
jstack –l pid
内存可见性
可见性介绍
可见性:一个线程对共享变量值的修改,能够及时地被其他线程看到。
共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。
Java内存模型(JMM)
Java内存模型(Java Memory Model)描述了程序中各种变量(线程共享变量)的访问规则,以及在Java中将变量存储到内存和从内存中读取出变量这样的底层细节。
所有变量都存储在主内存中
每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)。
线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写。
不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。
共享变量可见性实现的原理
线程1对共享变量的修改要想被线程2及时看到,必须要经过如下2个步骤:
把工作内存1中更新过的共享变量刷新到主内存中。
将主内存中最新的共享变量的值更新到工作内存2中。
可见性
要实现共享变量的可见性,必须保证两点:
线程修改后的共享变量值能够及时从工作内存刷新到主内存中。
其他线程能够及时把共享变量的最新值从主内存更新到自己的工作内存中。
可见性的实现方式
Java语言层面支持的可见性实现方式:
Synchronized
Volatile
Synchronized实现可见性
Synchronized能够实现:
原子性(同步);
可见性
JMM关于Synchronized的两条规定:
线程解锁前,必须把共享变量的最新值刷新到主内存中;
线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁)
线程解锁前对共享变量得修改在下次加锁时对其他线程可见。
线程执行互斥代码的过程:
获得互斥锁
清空工作内存
从主内存中拷贝变量的最新副本到工作内存
执行代码。
将更改后的共享变量的值刷新到主内存。
释放互斥锁。
重排序
重排序:代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化。
编译器优化的重排序(编译器优化)。
指令级并行重排序(处理器优化)。
内存系统的重排序(处理器优化)。
as-if-serial
as-if-serial:无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致(java编译器、运行时和处理器都会保证Java在单线程下遵循as-if-serial语义)。
例子:
Int num = 1;
Int num2 = 2;
Int sum = num+num2;
单线程:第1、2行的顺序可以重排,但第3行不能
重排序不会给单线程带来内存可见性问题
多线程中程序交错执行时,重排序可能会造成内存可见性问题。
Volatile实现可见性
Volatile关键字:
能够保证volatile变量的可见性
不能保证volatile变量复合操作的原子性
Volatile如何实现内存可见性:
In depth: It is achieved by adding memory barriers and prohibiting reordering optimization.
When a write operation is performed on a volatile variable, a store barrier instruction will be added after the write operation.
When a read operation is performed on a volatile variable, a load barrier instruction will be added before the read operation.
In layman's terms: Every time a volatile variable is accessed by a thread, the value of the variable is forced to be reread from the main memory. When the variable changes, the thread is forced to refresh the latest value to the main memory. In this way, different threads can always see the latest value of the variable at any time.
The process of thread writing volatile variables:
Change the value of the volatile variable copy in the thread's working memory
will be changed after The value of the copy is flushed from the working memory to the main memory
The process of thread reading volatile variables:
Reading volatile variables from main memory The latest value to the thread's working memory
Read a copy of the volatile variable from the working memory.
Volatile Applicable Occasions
To safely use volatile variables in multi-threads, you must also meet:
1. The writing operation to a variable does not depend on its current value
2. Boolean, used to record temperature
3. This variable is not included in an invariant with other variables.
Conclusion: Don’t care what others think about you behind your back, because these words can’t change the facts, but they may mess with your heart.