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之间是没有干扰的。这就是原子性的一个特点,不可被中断。