线程
线程:是进程中的单个顺序控制流,是一条执行路径
·单线程:一个进程如果只有一条执行路径,则称为单线程程序
·多线程:一个进程如果有多条执行程序,则成为多线程程序
进程:是正在运行的应用程序
有两种方法来创建一个新的执行线程:
一是声明一个类是Thread的子类。这类应重写类Thread的run方法。然后可以分配并启动子类的实例
run方法用来封装被线程执行的代码
package com._01; public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(i); } } }
package com._01; public class MyThreadDemo { public static void main(String[] args) { MyThread m1 = new MyThread(); MyThread m2 = new MyThread(); //void start():使此线程开始执行,Java虚拟机调用此线程的run方法 m1.start(); m2.start(); //这两个线程同时执行 } }
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Process finished with exit code 0
void setName(String name):将此线程的名称更改为等于参数name
String getName():返回此线程的名称
若要通过构造方法来设置线程的名称那么类中的带参构造方法需要调用super()方法
package com._01; public class MyThread extends Thread{ public MyThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(i); } } }
static Thread currentThread():返回对当前正在执行的线程对象的引用
package com._01; public class MyThreadDemo { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()); } }
运行结果:main
线程调度
线程有两种调度模型:
·分时调度模型:所有线程轮流使用CPU使用权,平均分配每个线程占用CPU的时间片
·抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取CPU的时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU,那么CPU在某一个时刻只能执行一条指令,线程只有得到CPU的时间片,也就是使用权,才可以执行指令,所以多线程程序的执行时随机性的,因为谁抢到CPU的使用权是不一定的。
Thread类中设置和获取优先级的方法
·public final int getPriority():返回此线程的优先级
`public final void setPriority():更改此线程的优先级
线程的优先级的值:1-10 默认值为5,特别注意线程的优先级高仅仅表示此线程获得CPU的时间片的几率高,并不是此线程优先执行,在次数比较多,或者多次运行的时候才能看到想要的效果
package com._01; public class MyThreadDemo { public static void main(String[] args) { MyThread m1 = new MyThread(); m1.setName("飞机"); MyThread m2 = new MyThread(); m2.setName("高铁"); MyThread m3 = new MyThread(); m3.setName("汽车"); //设置正确的优先级 m1.setPriority(10); m2.setPriority(5); m3.setPriority(1); m1.start(); m2.start(); m3.start(); } }
"C:\Program Files\Java\jdk1.8.0_192\bin\java.exe" "-javaagent:E:\IntelliJ IDEA Educational Edition 2019.3.1\lib\idea_rt.jar=51120:E:\IntelliJ IDEA Educational Edition 2019.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_192\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\rt.jar;F:\新建文件夹\MyThread\out\production\MyThread" com._01.MyThreadDemo 飞机,0 飞机,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 飞机,86 飞机,87 飞机,88 飞机,89 飞机,90 飞机,91 飞机,92 飞机,93 飞机,94 飞机,95 飞机,96 飞机,97 飞机,98 飞机,99 高铁,0 高铁,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 高铁,86 高铁,87 高铁,88 高铁,89 高铁,90 高铁,91 高铁,92 高铁,93 高铁,94 高铁,95 高铁,96 高铁,97 高铁,98 高铁,99 汽车,0 汽车,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 汽车,86 汽车,87 汽车,88 汽车,89 汽车,90 汽车,91 汽车,92 汽车,93 汽车,94 汽车,95 汽车,96 汽车,97 汽车,98 汽车,99
线程控制
static void sleep (long millis):使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join():等待这个线程死亡(意思是如果一个一个线程调用这个方法则其他的线程必须等待这个线程执行完毕才能执行)
void setDaemon(boolean on):使此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机退出
package com._01; public class MyThread extends Thread{ public MyThread(){} public MyThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+","+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
package com._01; public class MyThreadDemo { public static void main(String[] args) { MyThread m1 = new MyThread(); m1.setName("飞机"); MyThread m2 = new MyThread(); m2.setName("高铁"); MyThread m3 = new MyThread(); m3.setName("汽车"); m1.start(); m2.start(); m3.start(); } }
飞机,0 高铁,0 汽车,0 高铁,1 汽车,1 飞机,1 高铁,2 飞机,2 汽车,2 高铁,3 飞机,3 汽车,3 高铁,4 汽车,4 飞机,4
package com._01; public class MyThreadDemo { public static void main(String[] args) { MyThread m1 = new MyThread(); m1.setName("飞机"); MyThread m2 = new MyThread(); m2.setName("高铁"); MyThread m3 = new MyThread(); m3.setName("汽车"); m1.start(); try { m1.join(); } catch (InterruptedException e) { e.printStackTrace(); } m2.start(); m3.start(); } }
"C:\Program Files\Java\jdk1.8.0_192\bin\java.exe" "-javaagent:E:\IntelliJ IDEA Educational Edition 2019.3.1\lib\idea_rt.jar=51285:E:\IntelliJ IDEA Educational Edition 2019.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_192\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\rt.jar;F:\新建文件夹\MyThread\out\production\MyThread" com._01.MyThreadDemo 飞机,0 飞机,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 飞机,86 飞机,87 飞机,88 飞机,89 飞机,90 飞机,91 飞机,92 飞机,93 飞机,94 飞机,95 飞机,96 飞机,97 飞机,98 飞机,99 汽车,0 高铁,0 汽车,1 高铁,1 汽车,2 高铁,2 汽车,3 高铁,3 汽车,4 高铁,4 汽车,5 高铁,5 高铁,6 高铁,7 高铁,8 高铁,9 高铁,10 汽车,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 高铁,11 汽车,51 高铁,12 汽车,52 高铁,13 汽车,53 高铁,14 汽车,54 高铁,15 汽车,55 高铁,16 汽车,56 高铁,17 汽车,57 汽车,58 汽车,59 汽车,60 高铁,18 汽车,61 高铁,19 汽车,62 高铁,20 汽车,63 高铁,21 汽车,64 高铁,22 汽车,65 高铁,23 汽车,66 高铁,24 汽车,67 高铁,25 汽车,68 高铁,26 汽车,69 高铁,27 高铁,28 高铁,29 高铁,30 汽车,70 高铁,31 汽车,71 高铁,32 汽车,72 高铁,33 汽车,73 高铁,34 汽车,74 高铁,35 汽车,75 高铁,36 汽车,76 高铁,37 汽车,77 高铁,38 汽车,78 高铁,39 汽车,79 汽车,80 汽车,81 高铁,40 汽车,82 高铁,41 汽车,83 高铁,42 汽车,84 高铁,43 汽车,85 高铁,44 汽车,86 高铁,45 汽车,87 高铁,46 汽车,88 高铁,47 汽车,89 高铁,48 汽车,90 高铁,49 汽车,91 汽车,92 汽车,93 汽车,94 高铁,50 汽车,95 高铁,51 汽车,96 高铁,52 汽车,97 高铁,53 汽车,98 高铁,54 汽车,99 高铁,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 高铁,86 高铁,87 高铁,88 高铁,89 高铁,90 高铁,91 高铁,92 高铁,93 高铁,94 高铁,95 高铁,96 高铁,97 高铁,98 高铁,99 Process finished with exit code 0
package com._01; public class MyThreadDemo { public static void main(String[] args) { MyThread m1 = new MyThread(); m1.setName("张飞"); MyThread m2 = new MyThread(); m2.setName("关羽"); //设置刘备为主线程 Thread.currentThread().setName("刘备"); //设置守护线程 m1.setDaemon(true); m2.setDaemon(true); m1.start(); m2.start(); for (int i = 0; i <9 ; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } }
"C:\Program Files\Java\jdk1.8.0_192\bin\java.exe" "-javaagent:E:\IntelliJ IDEA Educational Edition 2019.3.1\lib\idea_rt.jar=51390:E:\IntelliJ IDEA Educational Edition 2019.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_192\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\rt.jar;F:\新建文件夹\MyThread\out\production\MyThread" com._01.MyThreadDemo 刘备:0 张飞,0 张飞,1 张飞,2 张飞,3 张飞,4 张飞,5 关羽,0 关羽,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 张飞,6 刘备:1 关羽,48 刘备:2 张飞,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 张飞,86 张飞,87 张飞,88 张飞,89 张飞,90 张飞,91 张飞,92 张飞,93 张飞,94 张飞,95 张飞,96 张飞,97 张飞,98 张飞,99 刘备:3 刘备:4 刘备:5 刘备:6 刘备:7 刘备:8 关羽,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 Process finished with exit code 0
线程的生命周期

第二种实现多线程的方式
-
声明一个类实现
Runnable接口。该类实现run()方法。然后可以分配类的实例。在创建Thread时作为作为参数传递 ,这种方式的好处:不影响这个类实现一个父类,可以看成同一个资源被多个线程使用
View Codepackage com._02; public class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i <100 ; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } }
View Codepackage com._02; public class MyRunnableDemo { public static void main(String[] args) { MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr);//默认线程名称 Thread t2 = new Thread(mr,"飞机");//设置线程名称 t1.start(); t2.start(); } }
线程同步
卖票案例
View Codepackage com._03; public class SellTicket implements Runnable{ //定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100; private int tickets = 100; //在SellTicket类中重写run()方法实现卖票,代码步骤如下 @Override public void run() { // A:判断票数大于0,就卖票,并告知是哪个窗口卖的 // B:卖了票之后,总票数要减1 // C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行 while (true) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } } }
View Codepackage com.itheima_07; /* 卖票案例的思考 */ public class SellTicketDemo { public static void main(String[] args) { SellTicket st = new SellTicket(); Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); t1.start(); t2.start(); t3.start(); } }
此程序有多条语句操作共享数据所以会造成数据安全问题。
判断多线程程序有数据安全问题的标准(三个都满足才有数据安全问题)
·是多线程环境
·有共享数据
·有多条语句操作共享数据
----解决方法-----
1.同步代码块
锁多条语句操作共享数据,可以使用同步代码块
格式:
synchronized(任意对象){
多条语句操作共享数据的代码
}
package com._03; public class SellTicket implements Runnable{ private Object object = new Object(); //定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100; private int tickets = 100; //在SellTicket类中重写run()方法实现卖票,代码步骤如下 @Override public void run() { // A:判断票数大于0,就卖票,并告知是哪个窗口卖的 // B:卖了票之后,总票数要减1 // C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行 while (true) { synchronized (object){ if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } } } }
-
同步方法:就是把synchronized关键字加到方法上
格式:修饰符 synchronized 返回值类型 方法名(方法参数){}
同步方法的锁对象是this对象
View Codepackage com._03; public class SellTicket implements Runnable { private Object object = new Object(); //定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100; private int tickets = 100; //在SellTicket类中重写run()方法实现卖票,代码步骤如下 @Override public void run() { // A:判断票数大于0,就卖票,并告知是哪个窗口卖的 // B:卖了票之后,总票数要减1 // C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行 while (true) { sell(); } } private synchronized void sell() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } }
同步静态方法:就是把synchronized加到静态方法上
格式:修饰符 static synchronized 返回值类型 方法名(方法参数){}
需要注意的若其他非静态方法调用静态方法则
synchronized(任意对象){
多条语句操作共享数据的代码
}
中的任意对象是 类名.class 这个用法会在反射里讲解
即同步静态方法的锁对象是类名.class
线程安全的类
StringBuffer:线性安全,可变的字符序列
从版本JDK5开始,被StringBuilder替代,通常应该使用StringBuilder类,因为他支持所有的操作,但他更改,因为他不执行同步。
Vector
从Java2平台v1.2开始,该类改进了List接口,使其成为Java Collections Framework的成员,与新的集合实现不同,Vector被同步,如果不需要线程安全的实现,建议使用ArrayList代替Vector
Hashtable
该类实现了一个哈希表,他将键映射到值,任何非null对象都可以用作建或者值
从Java2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为Java Collections Framework的成员。与新的集合实现不同,Hashtable呗同步。如果不需要线程安全的实现,建议使用HashMap代替Hashtable
Collections类中有一个方法:static<T> List<T> synchronizedlist(List<T> list ) 返回由指定列表支持的同步(线性安全)列表
Collections.synchronizedList(new ArrayList<String>());Lock锁
View Codepackage com.itheima_11; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* Lock中提供了获得锁和释放锁的方法 void lock():获得锁 void unlock():释放锁 Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化 ReentrantLock():创建一个ReentrantLock的实例 */ public class SellTicket implements Runnable { private int tickets = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try { lock.lock(); if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } } finally { lock.unlock(); } } } }
生产者消费者模式
![]()
![]()
生产者和消费者案例
Boxpackage com.itheima_12; public class Box { //定义一个成员变量,表示第x瓶奶 private int milk; //定义一个成员变量,表示奶箱的状态 private boolean state = false; //提供存储牛奶和获取牛奶的操作 public synchronized void put(int milk) { //如果有牛奶,等待消费 if(state) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有牛奶,就生产牛奶 this.milk = milk; System.out.println("送奶工将第" + this.milk + "瓶奶放入奶箱"); //生产完毕之后,修改奶箱状态 state = true; //唤醒其他等待的线程 notifyAll(); } public synchronized void get() { //如果没有牛奶,等待生产 if(!state) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果有牛奶,就消费牛奶 System.out.println("用户拿到第" + this.milk + "瓶奶"); //消费完毕之后,修改奶箱状态 state = false; //唤醒其他等待的线程 notifyAll(); } }
BoxDemopackage com.itheima_12; /* 生产者消费者案例中包含的类: 1:奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作 2:生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作 3:消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作 4:测试类(BoxDemo):里面有main方法,main方法中的代码步骤如下 A:创建奶箱对象,这是共享数据区域 B:创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 C:创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作 D:创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 E:启动线程 */ public class BoxDemo { public static void main(String[] args) { //创建奶箱对象,这是共享数据区域 Box b = new Box(); //创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 Producer p = new Producer(b); //创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作 Customer c = new Customer(b); //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 Thread t1 = new Thread(p); Thread t2 = new Thread(c); //启动线程 t1.start(); t2.start(); } }
Customerpackage com.itheima_12; public class Customer implements Runnable { private Box b; public Customer(Box b) { this.b = b; } @Override public void run() { while (true) { b.get(); } } }
Producerpackage com.itheima_12; public class Producer implements Runnable { private Box b; public Producer(Box b) { this.b = b; } @Override public void run() { for(int i=1; i<=30; i++) { b.put(i); } } }


浙公网安备 33010602011771号