线程同步问题
写一个模拟买票的程序
class Sell implements Runnable {
private int ticket = 3;
@Override
public void run() {
while(true){
if(this.ticket > 0){
System.out.println("【" + Thread.currentThread().getName()
+ "卖出的第" + ticket-- + "张票】");
} else {
break;
}
}
}
}
public class Windows {
public static void main(String[] args) {
Sell sell1 = new Sell();
Thread thread1 = new Thread(sell1,"窗口A");
Thread thread2 = new Thread(sell1,"窗口B");
Thread thread3 = new Thread(sell1,"窗口C");
thread1.start();
thread2.start();
thread3.start();
}
}
随机抽取其中的依次执行结果。
对于这种数据出现问题的情况,我们称为线程不同步。
对于线程不同步,我们可以采取一种有味道的方法来理解。
A和B同时去上厕所,并且这个厕所每次只能容纳一个人去方便;当A进去的时候,还没来得及蹲下,B就进来了,这时候就出现了一个马桶上承受着两个人的情况,这就会必然导致有一个人的排泄物出现在马桶外面的情况。这就对应着卖出第0张票的情况。
为了解决这个上厕所的问题,我们可以在厕所的门上设计一把锁,当A进入之后,先把门锁上,这时无论A在里面多久,无论蹲没蹲下,B都无法进入。这样就可以保证不会出现意外了。
因此为了线程同步,我们需要在代码上加一把所,这个锁就是synchronized。
同步代码块
我们把使数据发生变化的那段代码放入synchronized关键字定义的代码块中,就可以实现线程同步。
在这段代码中,对数据操作的代码是if语句,因此我们将if语句放在synchronized代码块中。
class Sell implements Runnable {
private int ticket = 3;
@Override
public void run() {
while (true) {
/*
在synchronized代码块执行的时候需要指定一个设置同步的
对象,显然操作的对象就是本对象,因此我们使用this
*/
synchronized (this) {
if (this.ticket > 0) {
System.out.println("【" + Thread.currentThread().getName()
+ "卖出的第" + ticket-- + "张票】");
} else {
break;
}
}
}
}
}
public class Windows {
public static void main(String[] args) {
Sell sell1 = new Sell();
Thread thread1 = new Thread(sell1, "窗口A");
Thread thread2 = new Thread(sell1, "窗口B");
Thread thread3 = new Thread(sell1, "窗口C");
thread1.start();
thread2.start();
thread3.start();
}
}
随机取其中的一次执行结果。
同步方法
直接将synchronized加在对数据操作的方法上,实现线程同步。
class Sell implements Runnable {
private int ticket = 3;
@Override
public synchronized void run() {
while (true) {
if (this.ticket > 0) {
System.out.println("【" + Thread.currentThread().getName()
+ "卖出的第" + ticket-- + "张票】");
} else {
break;
}
}
}
}
public class Windows {
public static void main(String[] args) {
Sell sell1 = new Sell();
Thread thread1 = new Thread(sell1, "窗口A");
Thread thread2 = new Thread(sell1, "窗口B");
Thread thread3 = new Thread(sell1, "窗口C");
thread1.start();
thread2.start();
thread3.start();
}
}
但是一旦涉及了同步,就意味着性能的下降。