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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
public class ThreadTest implements Runnable {

private int trainCount = 100;
private Object lock = new Object();//实例化一个对象当作锁

@Override
public void run() {
while (trainCount > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
sell();
}

}

public void sell () {
synchronized (lock) {
if (trainCount > 0) {
System.out.println(Thread.currentThread().getName() + " Sell a ticket:" + (100 - trainCount + 1));
trainCount--;
}
}
}


public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
Thread thread = new Thread(threadTest, "窗口①");
Thread thread2 = new Thread(threadTest, "窗口②");
thread.start();
thread2.start();

}
}

//运行结果
//窗口① Sell a ticket:1
// 窗口② Sell a ticket:2
// 窗口① Sell a ticket:3
// 窗口② Sell a ticket:4
// 窗口① Sell a ticket:5
// 窗口② Sell a ticket:6
// 窗口① Sell a ticket:7
// 窗口② Sell a ticket:8
// 窗口① Sell a ticket:9
// 窗口② Sell a ticket:10
// 窗口① Sell a ticket:11
// 窗口② Sell a ticket:12
// 窗口② Sell a ticket:13
// 窗口① Sell a ticket:14
// 窗口① Sell a ticket:15
// 窗口② Sell a ticket:16
// 窗口② Sell a ticket:17
// 窗口① Sell a ticket:18
// 窗口① Sell a ticket:19
// 窗口② Sell a ticket:20
// 窗口① Sell a ticket:21
// 窗口② Sell a ticket:22
// 窗口② Sell a ticket:23
// 窗口① Sell a ticket:24
// 窗口① Sell a ticket:25
// 窗口② Sell a ticket:26
// 窗口① Sell a ticket:27
// 窗口② Sell a ticket:28
// 窗口① Sell a ticket:29
// 窗口② Sell a ticket:30
// 窗口② Sell a ticket:31
// 窗口① Sell a ticket:32
// 窗口① Sell a ticket:33
// 窗口② Sell a ticket:34
// 窗口① Sell a ticket:35
// 窗口② Sell a ticket:36
// 窗口② Sell a ticket:37
// 窗口① Sell a ticket:38
// 窗口① Sell a ticket:39
// 窗口② Sell a ticket:40
// 窗口② Sell a ticket:41
// 窗口① Sell a ticket:42
// 窗口① Sell a ticket:43
// 窗口② Sell a ticket:44
// 窗口② Sell a ticket:45
// 窗口① Sell a ticket:46
// 窗口① Sell a ticket:47
// 窗口② Sell a ticket:48
// 窗口① Sell a ticket:49
// 窗口② Sell a ticket:50
// 窗口② Sell a ticket:51
// 窗口① Sell a ticket:52
// 窗口① Sell a ticket:53
// 窗口② Sell a ticket:54
// 窗口② Sell a ticket:55
// 窗口① Sell a ticket:56
// 窗口① Sell a ticket:57
// 窗口② Sell a ticket:58
// 窗口① Sell a ticket:59
// 窗口② Sell a ticket:60
// 窗口① Sell a ticket:61
// 窗口② Sell a ticket:62
// 窗口② Sell a ticket:63
// 窗口① Sell a ticket:64
// 窗口① Sell a ticket:65
// 窗口② Sell a ticket:66
// 窗口② Sell a ticket:67
// 窗口① Sell a ticket:68
// 窗口① Sell a ticket:69
// 窗口② Sell a ticket:70
// 窗口② Sell a ticket:71
// 窗口① Sell a ticket:72
// 窗口② Sell a ticket:73
// 窗口① Sell a ticket:74
// 窗口① Sell a ticket:75
// 窗口② Sell a ticket:76
// 窗口② Sell a ticket:77
// 窗口① Sell a ticket:78
// 窗口② Sell a ticket:79
// 窗口① Sell a ticket:80
// 窗口① Sell a ticket:81
// 窗口② Sell a ticket:82
// 窗口① Sell a ticket:83
// 窗口② Sell a ticket:84
// 窗口② Sell a ticket:85
// 窗口① Sell a ticket:86
// 窗口① Sell a ticket:87
// 窗口② Sell a ticket:88
// 窗口① Sell a ticket:89
// 窗口② Sell a ticket:90
// 窗口① Sell a ticket:91
// 窗口② Sell a ticket:92
// 窗口① Sell a ticket:93
// 窗口② Sell a ticket:94
// 窗口① Sell a ticket:95
// 窗口② Sell a ticket:96
// 窗口① Sell a ticket:97
// 窗口② Sell a ticket:98
// 窗口② Sell a ticket:99
// 窗口① Sell a ticket:100
//
// Process finished with exit code 0

上面代码使用了synchronized代码块进行数据的同步,使用synchronized的时候不要全部代码用synchronized代码块包裹,只要包裹可能会出现线程安全问题的地方就行了锁:
比如上厕所锁了门,必须要等里面的认出来了其他人才能抢厕所

使用synchronized的条件:
1.必须有两个线程以上,并且需要发生同步 2.多个线程同步,必须用同一把锁 3.保证只有一个线程进行执行

原理:
1.当一个线程拿到锁了,其他线程已经有cpu执行,需要排队等待其他线程释放锁。 2.代码执行完毕或者抛出异常是就会释放锁 3.锁被释放掉的话,其他贤臣刚开始抢夺锁进去同步中区

缺点:
死锁问题 效率非常低,因为多个线程还要抢夺锁耗费资源

保证线程的原子性 原子性:是指一个操作是不可中断的。即使是多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。     比如,对于一个静态全局变量int i,两个线程同时对它赋值,线程A给他赋值为1,线程B给他赋值为-1。那么不管这两个线程     以何种方式。何种步调工作,i的值要么是1,要么是-1.线程A和线程B之间是没有干扰的。这就是原子性的一个特点,不可被中断。