您的位置:首页 > 职场人生

黑马程序员_java多线程的同步和死锁

2015-11-10 13:18 691 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!
-------!--问题的导入每个线程都会有一个运行的时间片,都会有开始和时间片到期的时候。所以我们要注意了:一个线程的时间片到期的时候,此线程有可能执行到程序的任何一个位置而被暂停,然后就进入时间片的轮换,这样就导致多线程的运行结果不可意料。此时我们就需要对线程进行同步处理。!--分析:比如说对于买票系统如下:
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
/**

*@authorRollen-Holt

**/

class
hello
implements
Runnable{

public
void
run(){

for
(
int
i=
0
;i<
10
;++i){

if
(count>
0
){

try
{

Thread.sleep(
1000
);

}
catch
(InterruptedExceptione){

e.printStackTrace();

}

System.out.println(count--);

}

}

}
public
static
void
main(String[]args){

hellohe=
new
hello();

Threadh1=
new
Thread(he);

Threadh2=
new
Thread(he);

Threadh3=
new
Thread(he);

h1.start();

h2.start();

h3.start();

}

private
int
count=
5
;

}
【运行结果】:
5
4
3
2
1
0
-1
这里出现了-1,显然这个是错的。,应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,
其他的线程必须等到这个线程结束之后才能继续执行。
【使用线程同步解决问题】
采用同步的话,可以使用同步代码块和同步方法两种来完成。【同步代码块】:
语法格式:
synchronized(同步对象){
//需要同步的代码
}
但是一般都把当前对象this作为同步对象。
比如对于上面的买票的问题,如下:
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
/**

*@authorRollen-Holt

**/

class
hello
implements
Runnable{

public
void
run(){

for
(
int
i=
0
;i<
10
;++i){

synchronized
(
this
){

if
(count>
0
){

try
{

Thread.sleep(
1000
);

}
catch
(InterruptedExceptione){

e.printStackTrace();

}

System.out.println(count--);

}

}

}

}
public
static
void
main(String[]args){

hellohe=
new
hello();

Threadh1=
new
Thread(he);

Threadh2=
new
Thread(he);

Threadh3=
new
Thread(he);

h1.start();

h2.start();

h3.start();

}

private
int
count=
5
;

}
【运行结果】:(每一秒输出一个结果)
5
4
3
2
1
【同步方法】
也可以采用同步方法。
语法格式为synchronized方法返回类型方法名(参数列表){
//其他代码
}
现在,我们采用同步方法解决上面的问题。
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
/**

*@authorRollen-Holt

**/

class
hello
implements
Runnable{

public
void
run(){

for
(
int
i=
0
;i<
10
;
++i){

sale();

}

}
public
synchronized
void
sale(){

if
(count>
0
){

try
{

Thread.sleep(
1000
);

}
catch
(InterruptedExceptione){

e.printStackTrace();

}

System.out.println(count--);

}

}
public
static
void
main(String[]args){

hellohe=
new
hello();

Threadh1=
new
Thread(he);

Threadh2=
new
Thread(he);

Threadh3=
new
Thread(he);

h1.start();

h2.start();

h3.start();

}
private
int
count=
5
;

}
【运行结果】(每秒输出一个)
5
4
3
2
1
提醒一下,当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。
此处列举经典的生产者和消费者问题。
【生产者和消费者问题】
先看一段有问题的代码。
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
class
Info{
public
StringgetName(){

return
name;

}
public
void
setName(Stringname){

this
.name=name;

}
public
int
getAge(){

return
age;

}
public
void
setAge(
int
age){

this
.age=age;

}
private
Stringname=
"Rollen"
;

private
int
age=
20
;

}
/**

*生产者

**/

class
Producer
implements
Runnable{

private
Infoinfo=
null
;

Producer(Infoinfo){

this
.info=info;

}


public
void
run(){

boolean
flag=
false
;

for
(
int
i=
0
;i<
25
;++i){

if
(flag){

this
.info.setName(
"Rollen"
);

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

this
.info.setAge(
20
);

flag=
false
;

}
else
{

this
.info.setName(
"chunGe"
);

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

this
.info.setAge(
100
);

flag=
true
;

}

}

}

}

/**

*消费者类

**/

class
Consumer
implements
Runnable{

private
Infoinfo=
null
;

public
Consumer(Infoinfo){

this
.info=info;

}


public
void
run(){

for
(
int
i=
0
;i<
25
;++i){

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

System.out.println(
this
.info.getName()+
"<---->"
+
this
.info.getAge());

}

}

}
/**

*测试类

**/

class
hello{

public
static
void
main(String[]args){

Infoinfo=
new
Info();

Producerpro=
new
Producer(info);

Consumercon=
new
Consumer(info);

new
Thread(pro).start();

new
Thread(con).start();

}

}
【运行结果】:
Rollen<---->100
chunGe<---->20
chunGe<---->100
Rollen<---->100
chunGe<---->20
Rollen<---->100
Rollen<---->100
Rollen<---->100
chunGe<---->20
chunGe<---->20
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
大家可以从结果中看到,名字和年龄并没有对于。那么如何解决呢?
1)加入同步
2)加入等待和唤醒
先来看看加入同步会是如何。
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
class
Info{


public
StringgetName(){

return
name;

}
public
void
setName(Stringname){

this
.name=name;

}
public
int
getAge(){

return
age;

}
public
void
setAge(
int
age){

this
.age=age;

}
public
synchronized
void
set(Stringname,
int
age){

this
.name=name;

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

this
.age=age;

}


public
synchronized
void
get(){

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

System.out.println(
this
.getName()+
"<===>"
+
this
.getAge());

}

private
Stringname=
"Rollen"
;

private
int
age=
20
;

}
/**

*生产者

**/

class
Producer
implements
Runnable{

private
Infoinfo=
null
;
Producer(Infoinfo){

this
.info=info;

}
public
void
run(){

boolean
flag=
false
;

for
(
int
i=
0
;i<
25
;
++i){

if
(flag){


this
.info.set(
"Rollen"
,
20
);

flag=
false
;

}
else
{

this
.info.set(
"ChunGe"
,
100
);

flag=
true
;

}

}

}

}
/**

*消费者类

**/

class
Consumer
implements
Runnable{

private
Infoinfo=
null
;
public
Consumer(Infoinfo){

this
.info=info;

}
public
void
run(){

for
(
int
i=
0
;i<
25
;
++i){

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

this
.info.get();

}

}

}
/**

*测试类

**/

class
hello{

public
static
void
main(String[]args){

Infoinfo=
new
Info();

Producerpro=
new
Producer(info);

Consumercon=
new
Consumer(info);

new
Thread(pro).start();

new
Thread(con).start();

}

}
【运行结果】:
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
从运行结果来看,错乱的问题解决了,现在是Rollen对应20,ChunGe对于100
,但是还是出现了重复读取的问题,也肯定有重复覆盖的问题。如果想解决这个问题,就需要使用Object类帮忙了、
,我们可以使用其中的等待和唤醒操作。
要完成上面的功能,我们只需要修改Info类饥渴,在其中加上标志位,并且通过判断标志位完成等待和唤醒的操作,代码如下:
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
class
Info{


public
StringgetName(){

return
name;

}
public
void
setName(Stringname){

this
.name=name;

}
public
int
getAge(){

return
age;

}
public
void
setAge(
int
age){

this
.age=age;

}
public
synchronized
void
set(Stringname,
int
age){

if
(!flag){

try
{

super
.wait();

}
catch
(Exceptione){

e.printStackTrace();

}

}

this
.name=name;

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

this
.age=age;

flag=
false
;

super
.notify();

}


public
synchronized
void
get(){

if
(flag){

try
{

super
.wait();

}
catch
(Exceptione){

e.printStackTrace();

}

}


try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

System.out.println(
this
.getName()+
"<===>"
+
this
.getAge());

flag=
true
;

super
.notify();

}

private
Stringname=
"Rollen"
;

private
int
age=
20
;

private
boolean
flag=
false
;

}
/**

*生产者

**/

class
Producer
implements
Runnable{

private
Infoinfo=
null
;
Producer(Infoinfo){

this
.info=info;

}
public
void
run(){

boolean
flag=
false
;

for
(
int
i=
0
;i<
25
;
++i){

if
(flag){


this
.info.set(
"Rollen"
,
20
);

flag=
false
;

}
else
{

this
.info.set(
"ChunGe"
,
100
);

flag=
true
;

}

}

}

}
/**

*消费者类

**/

class
Consumer
implements
Runnable{

private
Infoinfo=
null
;
public
Consumer(Infoinfo){

this
.info=info;

}
public
void
run(){

for
(
int
i=
0
;i<
25
;
++i){

try
{

Thread.sleep(
100
);

}
catch
(Exceptione){

e.printStackTrace();

}

this
.info.get();

}

}

}
/**

*测试类

**/

class
hello{

public
static
void
main(String[]args){

Infoinfo=
new
Info();

Producerpro=
new
Producer(info);

Consumercon=
new
Consumer(info);

new
Thread(pro).start();

new
Thread(con).start();

}

}
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
【程序运行结果】:

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

ChunGe<===>
100

Rollen<===>
20

先在看结果就可以知道,之前的问题完全解决。

后语:多练习------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!
-------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: