线程
线程:是进程中的单个顺序控制流,是一条执行路径
·单线程:一个进程如果只有一条执行路径,则称为单线程程序
·多线程:一个进程如果有多条执行程序,则成为多线程程序
进程:是正在运行的应用程序
有两种方法来创建一个新的执行线程:
一是声明一个类是Thread的子类。这类应重写类Thread的run方法。然后可以分配并启动子类的实例
run方法用来封装被线程执行的代码
packagecom._01;public class MyThread extendsThread{
@Overridepublic voidrun() {for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
View Code
packagecom._01;public classMyThreadDemo {public static voidmain(String[] args) {
MyThread m1= newMyThread();
MyThread m2= newMyThread();//void start():使此线程开始执行,Java虚拟机调用此线程的run方法
m1.start();
m2.start();//这两个线程同时执行
}
}
View Code
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
99Process finished with exit code0
执行结果
void setName(String name):将此线程的名称更改为等于参数name
String getName():返回此线程的名称
若要通过构造方法来设置线程的名称那么类中的带参构造方法需要调用super()方法
packagecom._01;public class MyThread extendsThread{publicMyThread(String name) {super(name);
}
@Overridepublic voidrun() {for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
View Code
static Thread currentThread():返回对当前正在执行的线程对象的引用
packagecom._01;public classMyThreadDemo {public static voidmain(String[] args) {
System.out.println(Thread.currentThread().getName());
}
}
View Code
运行结果:main
线程调度
线程有两种调度模型:
·分时调度模型:所有线程轮流使用CPU使用权,平均分配每个线程占用CPU的时间片
·抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取CPU的时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU,那么CPU在某一个时刻只能执行一条指令,线程只有得到CPU的时间片,也就是使用权,才可以执行指令,所以多线程程序的执行时随机性的,因为谁抢到CPU的使用权是不一定的。
Thread类中设置和获取优先级的方法
·public final int getPriority():返回此线程的优先级
`public final void setPriority():更改此线程的优先级
线程的优先级的值:1-10 默认值为5,特别注意线程的优先级高仅仅表示此线程获得CPU的时间片的几率高,并不是此线程优先执行,在次数比较多,或者多次运行的时候才能看到想要的效果
packagecom._01;public classMyThreadDemo {public static voidmain(String[] args) {
MyThread m1= newMyThread();
m1.setName("飞机");
MyThread m2= newMyThread();
m2.setName("高铁");
MyThread m3= newMyThread();
m3.setName("汽车");//设置正确的优先级
m1.setPriority(10);
m2.setPriority(5);
m3.setPriority(1);
m1.start();
m2.start();
m3.start();
}
}
View Code
"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虚拟机退出
packagecom._01;public class MyThread extendsThread{publicMyThread(){}publicMyThread(String name) {super(name);
}
@Overridepublic voidrun() {for (int i = 0; i < 100; i++) {
System.out.println(getName()+","+i);try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
类
packagecom._01;public classMyThreadDemo {public static voidmain(String[] args) {
MyThread m1= newMyThread();
m1.setName("飞机");
MyThread m2= newMyThread();
m2.setName("高铁");
MyThread m3= newMyThread();
m3.setName("汽车");
m1.start();
m2.start();
m3.start();
}
}
main
飞机,0高铁,0汽车,0高铁,1汽车,1飞机,1高铁,2飞机,2汽车,2高铁,3飞机,3汽车,3高铁,4汽车,4飞机,4
执行结果
packagecom._01;public classMyThreadDemo {public static voidmain(String[] args) {
MyThread m1= newMyThread();
m1.setName("飞机");
MyThread m2= newMyThread();
m2.setName("高铁");
MyThread m3= newMyThread();
m3.setName("汽车");
m1.start();try{
m1.join();
}catch(InterruptedException e) {
e.printStackTrace();
}
m2.start();
m3.start();
}
}
join方法
"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高铁,99Process finished with exit code0
View Code
packagecom._01;public classMyThreadDemo {public static voidmain(String[] args) {
MyThread m1= newMyThread();
m1.setName("张飞");
MyThread m2= newMyThread();
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关羽,85Process finished with exit code0
执行结果
线程的生命周期
第二种实现多线程的方式
声明一个类实现Runnable接口。该类实现run()方法。然后可以分配类的实例。在创建Thread时作为作为参数传递 ,这种方式的好处:不影响这个类实现一个父类,可以看成同一个资源被多个线程使用
packagecom._02;public class MyRunnable implementsRunnable {
@Overridepublic voidrun() {for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
View Code
packagecom._02;public classMyRunnableDemo {public static voidmain(String[] args) {
MyRunnable mr= newMyRunnable();
Thread t1= new Thread(mr);//默认线程名称
Thread t2 = new Thread(mr,"飞机");//设置线程名称
t1.start();
t2.start();
}
}
View Code
线程同步
卖票案例
packagecom._03;public class SellTicket implementsRunnable{//定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100;
private int tickets = 100;//在SellTicket类中重写run()方法实现卖票,代码步骤如下
@Overridepublic voidrun() {//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 Code
packagecom.itheima_07;/*卖票案例的思考*/
public classSellTicketDemo {public static voidmain(String[] args) {
SellTicket st= newSellTicket();
Thread t1= new Thread(st, "窗口1");
Thread t2= new Thread(st, "窗口2");
Thread t3= new Thread(st, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
View Code
此程序有多条语句操作共享数据所以会造成数据安全问题。
判断多线程程序有数据安全问题的标准(三个都满足才有数据安全问题)
·是多线程环境
·有共享数据
·有多条语句操作共享数据
----解决方法-----
1.同步代码块
锁多条语句操作共享数据,可以使用同步代码块
格式:
synchronized(任意对象){
多条语句操作共享数据的代码
}
packagecom._03;public class SellTicket implementsRunnable{private Object object = newObject();//定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100;
private int tickets = 100;//在SellTicket类中重写run()方法实现卖票,代码步骤如下
@Overridepublic voidrun() {//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--;
}
}
}
}
}
View Code
同步方法:就是把synchronized关键字加到方法上
格式:修饰符 synchronized 返回值类型 方法名(方法参数){}
同步方法的锁对象是this对象
packagecom._03;public class SellTicket implementsRunnable {private Object object = newObject();//定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:private int tickets = 100;
private int tickets = 100;//在SellTicket类中重写run()方法实现卖票,代码步骤如下
@Overridepublic voidrun() {//A:判断票数大于0,就卖票,并告知是哪个窗口卖的//B:卖了票之后,总票数要减1//C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行
while (true) {
sell();
}
}private synchronized voidsell() {if (tickets > 0) {try{
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + tickets + "张票");
tickets--;
}
}
}
View Code
同步静态方法:就是把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 List synchronizedlist(List list ) 返回由指定列表支持的同步(线性安全)列表
Collections.synchronizedList(new ArrayList());
Lock锁
packagecom.itheima_11;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;/*Lock中提供了获得锁和释放锁的方法
void lock():获得锁
void unlock():释放锁
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock():创建一个ReentrantLock的实例*/
public class SellTicket implementsRunnable {private int tickets = 100;private Lock lock = newReentrantLock();
@Overridepublic voidrun() {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();
}
}
}
}
View Code
生产者消费者模式
生产者和消费者案例
packagecom.itheima_12;public classBox {//定义一个成员变量,表示第x瓶奶
private intmilk;//定义一个成员变量,表示奶箱的状态
private boolean state = false;//提供存储牛奶和获取牛奶的操作
public synchronized void put(intmilk) {//如果有牛奶,等待消费
if(state) {try{
wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}//如果没有牛奶,就生产牛奶
this.milk =milk;
System.out.println("送奶工将第" + this.milk + "瓶奶放入奶箱");//生产完毕之后,修改奶箱状态
state = true;//唤醒其他等待的线程
notifyAll();
}public synchronized voidget() {//如果没有牛奶,等待生产
if(!state) {try{
wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}//如果有牛奶,就消费牛奶
System.out.println("用户拿到第" + this.milk + "瓶奶");//消费完毕之后,修改奶箱状态
state = false;//唤醒其他等待的线程
notifyAll();
}
}
Box
packagecom.itheima_12;/*生产者消费者案例中包含的类:
1:奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作
2:生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
3:消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作
4:测试类(BoxDemo):里面有main方法,main方法中的代码步骤如下
A:创建奶箱对象,这是共享数据区域
B:创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
C:创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
D:创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
E:启动线程*/
public classBoxDemo {public static voidmain(String[] args) {//创建奶箱对象,这是共享数据区域
Box b = newBox();//创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
Producer p = newProducer(b);//创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
Customer c = newCustomer(b);//创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
Thread t1 = newThread(p);
Thread t2= newThread(c);//启动线程
t1.start();
t2.start();
}
}
BoxDemo
packagecom.itheima_12;public class Customer implementsRunnable {privateBox b;publicCustomer(Box b) {this.b =b;
}
@Overridepublic voidrun() {while (true) {
b.get();
}
}
}
Customer
packagecom.itheima_12;public class Producer implementsRunnable {privateBox b;publicProducer(Box b) {this.b =b;
}
@Overridepublic voidrun() {for(int i=1; i<=30; i++) {
b.put(i);
}
}
}
Producer