线程安全问题
–如有想法或者建议,欢迎指出,感激不尽
简易售票机step:
1、任务:两个售票机同时对100张票进行交替售卖:
public class Ticket {
private int num;//票号
public Ticket(int num) {
this.num = num;
}
/**
* @return
* @Param
* @description 判断是否售卖完毕
* @date 2019/8/9 15:17
*/
public boolean sellOut() {
if (num <= 0) {
return true;
} else {
return false;
}
}
/**
* @return
* @Param
* @description 进行售卖票务
* @date 2019/8/9 15:18
*/
public void sellTickets() {
if (!sellOut()) {
System.out.println(Thread.currentThread().getName() + "当前票号为" + num);
num--;
}
}
}
2、定义售卖任务:(创建线程,重写run方法)
public class Seller extends Thread {
private Ticket ticket ;
public Seller(Ticket ticket){
this.ticket = ticket;
}
@Override
public void run() {
while(true){
//执行售卖任务,每一个线程执行每一个售卖票的任务
ticket.sellTickets();
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3、测试:
public class SellerTest {
public static void main(String[] args) {
Ticket ticket = new Ticket(100);
//进行测试
Seller seller1 = new Seller(ticket);
Seller seller2 = new Seller(ticket);
seller1.start();
seller2.start();
}
}
4、结果:
Thread-1当前票号为50
Thread-0当前票号为50
Thread-1当前票号为48
Thread-0当前票号为48
Thread-1当前票号为46
Thread-0当前票号为45
Thread-0当前票号为44
Thread-1当前票号为44
Thread-1当前票号为42
Thread-0当前票号为42
Thread-0当前票号为40
Thread-1当前票号为40
Thread-0当前票号为38
Thread-1当前票号为37
Thread-0当前票号为36
Thread-1当前票号为35
Thread-0当前票号为34
Thread-1当前票号为34
Thread-1当前票号为32
Thread-0当前票号为31
Thread-0当前票号为30
Thread-1当前票号为30
Thread-1当前票号为28
Thread-0当前票号为28
Thread-0当前票号为26
Thread-1当前票号为25
Thread-0当前票号为24
Thread-1当前票号为24
Thread-1当前票号为22
Thread-0当前票号为22
Thread-0当前票号为20
Thread-1当前票号为19
Thread-0当前票号为18
Thread-1当前票号为17
Thread-0当前票号为16
Thread-1当前票号为15
Thread-0当前票号为14
Thread-1当前票号为13
Thread-0当前票号为12
Thread-1当前票号为11
Thread-0当前票号为10
Thread-1当前票号为9
Thread-0当前票号为8
Thread-1当前票号为7
Thread-0当前票号为6
Thread-1当前票号为5
Thread-0当前票号为4
Thread-1当前票号为3
Thread-0当前票号为2
Thread-1当前票号为1
Process finished with exit code 0
此时引入线程非安全的问题:
1号售票机刚进入方法准备售票,2号售票机就进入方法拿到同一张ticket,怕是要打架哦。现实情况不应该也不会出现这样的情况,此时我们可以认为这是一个非线程安全的情况。出现这样的情况主要是因为他们共享同一个变量ticket。
于是引入线程安全的结论:
不管这些线程如何交替执行,主程序不需要做任何的同步。结果都是与现实情况相符,都是正确行为,可以说这个程序是线程安全的。
如何解决线程非安全的情况:
synchronized:
锁方法
public synchronized void sellTickets() {
if (!sellOut()) {
System.out.println(Thread.currentThread().getName() + "当前票号为" + num);
num--;
}
}
锁对象
public void sellTickets() {
synchronized (this){
if (!sellOut()) {
System.out.println(Thread.currentThread().getName() + "当前票号为" + num);
num--;
}
}
结果:
Thread-0当前票号为50
Thread-1当前票号为49
Thread-0当前票号为48
Thread-1当前票号为47
Thread-0当前票号为46
Thread-1当前票号为45
Thread-0当前票号为44
Thread-1当前票号为43
Thread-0当前票号为42
Thread-1当前票号为41
Thread-0当前票号为40
Thread-1当前票号为39
Thread-0当前票号为38
Thread-1当前票号为37
Thread-0当前票号为36
Thread-1当前票号为35
Thread-0当前票号为34
Thread-1当前票号为33
Thread-0当前票号为32
Thread-1当前票号为31
Thread-0当前票号为30
Thread-1当前票号为29
Thread-0当前票号为28
Thread-1当前票号为27
Thread-0当前票号为26
Thread-1当前票号为25
Thread-0当前票号为24
Thread-1当前票号为23
Thread-0当前票号为22
Thread-1当前票号为21
Thread-0当前票号为20
Thread-1当前票号为19
Thread-0当前票号为18
Thread-1当前票号为17
Thread-0当前票号为16
Thread-1当前票号为15
Thread-0当前票号为14
Thread-1当前票号为13
Thread-0当前票号为12
Thread-1当前票号为11
Thread-0当前票号为10
Thread-1当前票号为9
Thread-0当前票号为8
Thread-1当前票号为7
Thread-0当前票号为6
Thread-1当前票号为5
Thread-0当前票号为4
Thread-1当前票号为3
Thread-0当前票号为2
Thread-1当前票号为1
Process finished with exit code 0