代码实现:
/**
* 多线程模拟售票,基于Thread
*/
public class TicketSalesByThread {
public static void main(String[] args) {
SellTicket sellTicket = new SellTicket();
SellTicket sellTicket1 = new SellTicket();
SellTicket sellTicket2 = new SellTicket();
sellTicket.start();
sellTicket1.start();
sellTicket2.start();
}
}
class SellTicket extends Thread {
// 余票
private static int ticketNum = 100;
@Override
public void run() {
while (true) {
if (ticketNum <= 0) {
System.out.println("没有余票!");
break;
}
// 休眠卖票
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("窗口" + Thread.currentThread().getName() +
"售出一张票。" + "剩余票数:" + (--ticketNum));
}
}
}
结果分析:
窗口Thread-1售出一张票。剩余票数:97
窗口Thread-0售出一张票。剩余票数:98
窗口Thread-2售出一张票。剩余票数:99
窗口Thread-0售出一张票。剩余票数:96
窗口Thread-1售出一张票。剩余票数:96
窗口Thread-2售出一张票。剩余票数:95
窗口Thread-0售出一张票。剩余票数:94
窗口Thread-1售出一张票。剩余票数:93
窗口Thread-2售出一张票。剩余票数:92
窗口Thread-0售出一张票。剩余票数:91
窗口Thread-1售出一张票。剩余票数:90
窗口Thread-2售出一张票。剩余票数:89
窗口Thread-0售出一张票。剩余票数:88
窗口Thread-1售出一张票。剩余票数:87
窗口Thread-2售出一张票。剩余票数:86
窗口Thread-0售出一张票。剩余票数:85
窗口Thread-1售出一张票。剩余票数:84
窗口Thread-2售出一张票。剩余票数:83
窗口Thread-0售出一张票。剩余票数:82
窗口Thread-1售出一张票。剩余票数:81
窗口Thread-2售出一张票。剩余票数:80
窗口Thread-0售出一张票。剩余票数:79
窗口Thread-1售出一张票。剩余票数:78
窗口Thread-2售出一张票。剩余票数:77
窗口Thread-0售出一张票。剩余票数:76
窗口Thread-1售出一张票。剩余票数:75
窗口Thread-2售出一张票。剩余票数:74
窗口Thread-0售出一张票。剩余票数:73
窗口Thread-1售出一张票。剩余票数:72
窗口Thread-2售出一张票。剩余票数:71
窗口Thread-0售出一张票。剩余票数:70
窗口Thread-1售出一张票。剩余票数:69
窗口Thread-2售出一张票。剩余票数:68
窗口Thread-0售出一张票。剩余票数:67
窗口Thread-1售出一张票。剩余票数:66
窗口Thread-2售出一张票。剩余票数:65
窗口Thread-0售出一张票。剩余票数:64
窗口Thread-1售出一张票。剩余票数:63
窗口Thread-2售出一张票。剩余票数:62
窗口Thread-0售出一张票。剩余票数:61
窗口Thread-1售出一张票。剩余票数:60
窗口Thread-2售出一张票。剩余票数:59
窗口Thread-0售出一张票。剩余票数:58
窗口Thread-1售出一张票。剩余票数:57
窗口Thread-2售出一张票。剩余票数:56
窗口Thread-0售出一张票。剩余票数:55
窗口Thread-1售出一张票。剩余票数:54
窗口Thread-2售出一张票。剩余票数:53
窗口Thread-0售出一张票。剩余票数:52
窗口Thread-1售出一张票。剩余票数:51
窗口Thread-2售出一张票。剩余票数:50
窗口Thread-0售出一张票。剩余票数:49
窗口Thread-1售出一张票。剩余票数:48
窗口Thread-2售出一张票。剩余票数:47
窗口Thread-0售出一张票。剩余票数:46
窗口Thread-1售出一张票。剩余票数:45
窗口Thread-2售出一张票。剩余票数:44
窗口Thread-0售出一张票。剩余票数:43
窗口Thread-1售出一张票。剩余票数:42
窗口Thread-2售出一张票。剩余票数:41
窗口Thread-0售出一张票。剩余票数:40
窗口Thread-1售出一张票。剩余票数:39
窗口Thread-2售出一张票。剩余票数:38
窗口Thread-0售出一张票。剩余票数:37
窗口Thread-1售出一张票。剩余票数:36
窗口Thread-2售出一张票。剩余票数:35
窗口Thread-0售出一张票。剩余票数:34
窗口Thread-1售出一张票。剩余票数:33
窗口Thread-2售出一张票。剩余票数:32
窗口Thread-0售出一张票。剩余票数:31
窗口Thread-1售出一张票。剩余票数:30
窗口Thread-2售出一张票。剩余票数:29
窗口Thread-0售出一张票。剩余票数:28
窗口Thread-1售出一张票。剩余票数:27
窗口Thread-2售出一张票。剩余票数:26
窗口Thread-0售出一张票。剩余票数:25
窗口Thread-1售出一张票。剩余票数:24
窗口Thread-2售出一张票。剩余票数:23
窗口Thread-0售出一张票。剩余票数:22
窗口Thread-1售出一张票。剩余票数:21
窗口Thread-2售出一张票。剩余票数:20
窗口Thread-0售出一张票。剩余票数:19
窗口Thread-1售出一张票。剩余票数:18
窗口Thread-2售出一张票。剩余票数:17
窗口Thread-0售出一张票。剩余票数:16
窗口Thread-1售出一张票。剩余票数:15
窗口Thread-2售出一张票。剩余票数:14
窗口Thread-0售出一张票。剩余票数:13
窗口Thread-1售出一张票。剩余票数:12
窗口Thread-2售出一张票。剩余票数:11
窗口Thread-0售出一张票。剩余票数:10
窗口Thread-1售出一张票。剩余票数:9
窗口Thread-2售出一张票。剩余票数:8
窗口Thread-0售出一张票。剩余票数:7
窗口Thread-1售出一张票。剩余票数:6
窗口Thread-2售出一张票。剩余票数:5
窗口Thread-0售出一张票。剩余票数:4
窗口Thread-1售出一张票。剩余票数:3
窗口Thread-2售出一张票。剩余票数:2
窗口Thread-0售出一张票。剩余票数:1
窗口Thread-1售出一张票。剩余票数:0
没有余票!
窗口Thread-2售出一张票。剩余票数:-1
没有余票!
窗口Thread-0售出一张票。剩余票数:-2
没有余票!
可以看到,基于
Thread的实现,出现了明显的超卖现象!😶🌫️
那么,为什么会发生这种情况呢?
原因分析:
当一个窗口还未执行--ticketNum操作时,另一个窗口已经进行售票状态,跳过了while循环的限制
代码实现:
/**
* 多线程模拟售票,基于实现Runnable接口
*/
public class TicketSalesByRunnable {
public static void main(String[] args) {
SellTicket02 sellTicket02 = new SellTicket02();
new Thread(sellTicket02).start();
new Thread(sellTicket02).start();
new Thread(sellTicket02).start();
}
}
class SellTicket02 implements Runnable {
private int ticketNum = 100;
@Override
public void run() {
while (true) {
if (ticketNum <= 0) {
System.out.println("没有余票!");
break;
}
// 休眠卖票
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("窗口" + Thread.currentThread().getName() +
"售出一张票。" + "剩余票数:" + (--ticketNum));
}
}
}
结果分析:
窗口Thread-0售出一张票。剩余票数:99
窗口Thread-2售出一张票。剩余票数:98
窗口Thread-1售出一张票。剩余票数:98
窗口Thread-0售出一张票。剩余票数:97
窗口Thread-2售出一张票。剩余票数:96
窗口Thread-1售出一张票。剩余票数:95
窗口Thread-0售出一张票。剩余票数:94
窗口Thread-2售出一张票。剩余票数:94
窗口Thread-1售出一张票。剩余票数:93
窗口Thread-2售出一张票。剩余票数:92
窗口Thread-0售出一张票。剩余票数:91
窗口Thread-1售出一张票。剩余票数:90
窗口Thread-2售出一张票。剩余票数:89
窗口Thread-0售出一张票。剩余票数:88
窗口Thread-1售出一张票。剩余票数:87
窗口Thread-0售出一张票。剩余票数:86
窗口Thread-2售出一张票。剩余票数:85
窗口Thread-1售出一张票。剩余票数:84
窗口Thread-2售出一张票。剩余票数:83
窗口Thread-0售出一张票。剩余票数:83
窗口Thread-1售出一张票。剩余票数:82
窗口Thread-2售出一张票。剩余票数:80
窗口Thread-0售出一张票。剩余票数:81
窗口Thread-1售出一张票。剩余票数:79
窗口Thread-2售出一张票。剩余票数:77
窗口Thread-0售出一张票。剩余票数:78
窗口Thread-1售出一张票。剩余票数:76
窗口Thread-2售出一张票。剩余票数:75
窗口Thread-0售出一张票。剩余票数:74
窗口Thread-1售出一张票。剩余票数:73
窗口Thread-2售出一张票。剩余票数:72
窗口Thread-0售出一张票。剩余票数:71
窗口Thread-1售出一张票。剩余票数:70
窗口Thread-2售出一张票。剩余票数:69
窗口Thread-0售出一张票。剩余票数:68
窗口Thread-1售出一张票。剩余票数:67
窗口Thread-2售出一张票。剩余票数:66
窗口Thread-0售出一张票。剩余票数:65
窗口Thread-1售出一张票。剩余票数:64
窗口Thread-2售出一张票。剩余票数:63
窗口Thread-0售出一张票。剩余票数:62
窗口Thread-1售出一张票。剩余票数:61
窗口Thread-2售出一张票。剩余票数:60
窗口Thread-0售出一张票。剩余票数:59
窗口Thread-1售出一张票。剩余票数:58
窗口Thread-2售出一张票。剩余票数:57
窗口Thread-0售出一张票。剩余票数:56
窗口Thread-1售出一张票。剩余票数:55
窗口Thread-2售出一张票。剩余票数:54
窗口Thread-0售出一张票。剩余票数:53
窗口Thread-1售出一张票。剩余票数:52
窗口Thread-2售出一张票。剩余票数:51
窗口Thread-0售出一张票。剩余票数:50
窗口Thread-1售出一张票。剩余票数:49
窗口Thread-2售出一张票。剩余票数:48
窗口Thread-0售出一张票。剩余票数:47
窗口Thread-1售出一张票。剩余票数:46
窗口Thread-2售出一张票。剩余票数:45
窗口Thread-0售出一张票。剩余票数:44
窗口Thread-1售出一张票。剩余票数:43
窗口Thread-2售出一张票。剩余票数:42
窗口Thread-0售出一张票。剩余票数:41
窗口Thread-1售出一张票。剩余票数:40
窗口Thread-2售出一张票。剩余票数:39
窗口Thread-0售出一张票。剩余票数:38
窗口Thread-1售出一张票。剩余票数:37
窗口Thread-2售出一张票。剩余票数:36
窗口Thread-0售出一张票。剩余票数:35
窗口Thread-1售出一张票。剩余票数:34
窗口Thread-2售出一张票。剩余票数:33
窗口Thread-0售出一张票。剩余票数:32
窗口Thread-1售出一张票。剩余票数:31
窗口Thread-2售出一张票。剩余票数:30
窗口Thread-0售出一张票。剩余票数:29
窗口Thread-1售出一张票。剩余票数:28
窗口Thread-2售出一张票。剩余票数:27
窗口Thread-0售出一张票。剩余票数:26
窗口Thread-1售出一张票。剩余票数:25
窗口Thread-2售出一张票。剩余票数:24
窗口Thread-0售出一张票。剩余票数:23
窗口Thread-1售出一张票。剩余票数:22
窗口Thread-2售出一张票。剩余票数:21
窗口Thread-0售出一张票。剩余票数:20
窗口Thread-1售出一张票。剩余票数:19
窗口Thread-2售出一张票。剩余票数:18
窗口Thread-0售出一张票。剩余票数:17
窗口Thread-1售出一张票。剩余票数:16
窗口Thread-2售出一张票。剩余票数:15
窗口Thread-0售出一张票。剩余票数:14
窗口Thread-1售出一张票。剩余票数:13
窗口Thread-2售出一张票。剩余票数:12
窗口Thread-0售出一张票。剩余票数:11
窗口Thread-1售出一张票。剩余票数:10
窗口Thread-2售出一张票。剩余票数:9
窗口Thread-0售出一张票。剩余票数:8
窗口Thread-1售出一张票。剩余票数:7
窗口Thread-2售出一张票。剩余票数:6
窗口Thread-0售出一张票。剩余票数:5
窗口Thread-1售出一张票。剩余票数:4
窗口Thread-2售出一张票。剩余票数:3
窗口Thread-0售出一张票。剩余票数:2
窗口Thread-1售出一张票。剩余票数:1
窗口Thread-2售出一张票。剩余票数:0
没有余票!
窗口Thread-0售出一张票。剩余票数:-1
没有余票!
窗口Thread-1售出一张票。剩余票数:-2
没有余票!
仍然会有超卖现象发生!
有时候,我们需要不同的线程可以相互控制对方的运行
可以采用通知线程中止来解决此类问题,比如我们简单实现一个DEMO,实现主线程通知中止其他线程的效果:
/**
* 通知线程中止
*/
public class ThreadExit {
public static void main(String[] args) throws InterruptedException {
TTT ttt = new TTT();
ttt.start();
Thread.sleep(5000);
// 主线程通知其他线程退出
ttt.setLoop(false);
}
}
class TTT extends Thread {
// 控制变量
private boolean loop = true;
@Override
public void run() {
while (loop) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("TTT线程正在运行...");
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
TTT线程会运行5秒,随后由主线程通知退出🤖
在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时就可以使用同步访问技术,保证数据在同一时刻只能有一个线程访问,以保证数据的完整性
synchronized线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作🤖
上成品代码:
/**
* 使用同步机制解决售票问题的超卖现象
*/
public class TicketSalesResult {
public static void main(String[] args) {
SellTicketRes sellTicketRes = new SellTicketRes();
new Thread(sellTicketRes).start();
new Thread(sellTicketRes).start();
new Thread(sellTicketRes).start();
}
}
class SellTicketRes implements Runnable {
private int ticketNum = 100;
private boolean loop = true;
/**
* 使用synchronized实现线程同步,解决超卖
*/
public synchronized void Sell() {
if (ticketNum <= 0) {
System.out.println("没有余票!");
loop = false;
return;
}
// 休眠卖票
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("窗口" + Thread.currentThread().getName() +
"售出一张票。" + "剩余票数:" + (--ticketNum));
}
@Override
public void run() {
while (true) {
if (loop == false) {
break;
}
Sell();
}
}
}
结果分析:(完美解决超卖问题)
窗口Thread-0售出一张票。剩余票数:99
窗口Thread-0售出一张票。剩余票数:98
窗口Thread-0售出一张票。剩余票数:97
窗口Thread-0售出一张票。剩余票数:96
窗口Thread-0售出一张票。剩余票数:95
窗口Thread-0售出一张票。剩余票数:94
窗口Thread-0售出一张票。剩余票数:93
窗口Thread-0售出一张票。剩余票数:92
窗口Thread-0售出一张票。剩余票数:91
窗口Thread-0售出一张票。剩余票数:90
窗口Thread-0售出一张票。剩余票数:89
窗口Thread-0售出一张票。剩余票数:88
窗口Thread-0售出一张票。剩余票数:87
窗口Thread-0售出一张票。剩余票数:86
窗口Thread-0售出一张票。剩余票数:85
窗口Thread-0售出一张票。剩余票数:84
窗口Thread-0售出一张票。剩余票数:83
窗口Thread-0售出一张票。剩余票数:82
窗口Thread-0售出一张票。剩余票数:81
窗口Thread-0售出一张票。剩余票数:80
窗口Thread-2售出一张票。剩余票数:79
窗口Thread-2售出一张票。剩余票数:78
窗口Thread-2售出一张票。剩余票数:77
窗口Thread-2售出一张票。剩余票数:76
窗口Thread-2售出一张票。剩余票数:75
窗口Thread-2售出一张票。剩余票数:74
窗口Thread-2售出一张票。剩余票数:73
窗口Thread-2售出一张票。剩余票数:72
窗口Thread-2售出一张票。剩余票数:71
窗口Thread-1售出一张票。剩余票数:70
窗口Thread-1售出一张票。剩余票数:69
窗口Thread-1售出一张票。剩余票数:68
窗口Thread-1售出一张票。剩余票数:67
窗口Thread-1售出一张票。剩余票数:66
窗口Thread-1售出一张票。剩余票数:65
窗口Thread-1售出一张票。剩余票数:64
窗口Thread-1售出一张票。剩余票数:63
窗口Thread-1售出一张票。剩余票数:62
窗口Thread-1售出一张票。剩余票数:61
窗口Thread-1售出一张票。剩余票数:60
窗口Thread-1售出一张票。剩余票数:59
窗口Thread-1售出一张票。剩余票数:58
窗口Thread-1售出一张票。剩余票数:57
窗口Thread-1售出一张票。剩余票数:56
窗口Thread-1售出一张票。剩余票数:55
窗口Thread-1售出一张票。剩余票数:54
窗口Thread-1售出一张票。剩余票数:53
窗口Thread-1售出一张票。剩余票数:52
窗口Thread-1售出一张票。剩余票数:51
窗口Thread-1售出一张票。剩余票数:50
窗口Thread-1售出一张票。剩余票数:49
窗口Thread-1售出一张票。剩余票数:48
窗口Thread-1售出一张票。剩余票数:47
窗口Thread-1售出一张票。剩余票数:46
窗口Thread-1售出一张票。剩余票数:45
窗口Thread-1售出一张票。剩余票数:44
窗口Thread-1售出一张票。剩余票数:43
窗口Thread-1售出一张票。剩余票数:42
窗口Thread-2售出一张票。剩余票数:41
窗口Thread-2售出一张票。剩余票数:40
窗口Thread-2售出一张票。剩余票数:39
窗口Thread-2售出一张票。剩余票数:38
窗口Thread-2售出一张票。剩余票数:37
窗口Thread-2售出一张票。剩余票数:36
窗口Thread-2售出一张票。剩余票数:35
窗口Thread-2售出一张票。剩余票数:34
窗口Thread-2售出一张票。剩余票数:33
窗口Thread-2售出一张票。剩余票数:32
窗口Thread-2售出一张票。剩余票数:31
窗口Thread-2售出一张票。剩余票数:30
窗口Thread-2售出一张票。剩余票数:29
窗口Thread-2售出一张票。剩余票数:28
窗口Thread-2售出一张票。剩余票数:27
窗口Thread-2售出一张票。剩余票数:26
窗口Thread-2售出一张票。剩余票数:25
窗口Thread-2售出一张票。剩余票数:24
窗口Thread-2售出一张票。剩余票数:23
窗口Thread-2售出一张票。剩余票数:22
窗口Thread-2售出一张票。剩余票数:21
窗口Thread-2售出一张票。剩余票数:20
窗口Thread-2售出一张票。剩余票数:19
窗口Thread-2售出一张票。剩余票数:18
窗口Thread-2售出一张票。剩余票数:17
窗口Thread-2售出一张票。剩余票数:16
窗口Thread-0售出一张票。剩余票数:15
窗口Thread-0售出一张票。剩余票数:14
窗口Thread-0售出一张票。剩余票数:13
窗口Thread-0售出一张票。剩余票数:12
窗口Thread-0售出一张票。剩余票数:11
窗口Thread-0售出一张票。剩余票数:10
窗口Thread-0售出一张票。剩余票数:9
窗口Thread-0售出一张票。剩余票数:8
窗口Thread-0售出一张票。剩余票数:7
窗口Thread-2售出一张票。剩余票数:6
窗口Thread-2售出一张票。剩余票数:5
窗口Thread-2售出一张票。剩余票数:4
窗口Thread-2售出一张票。剩余票数:3
窗口Thread-2售出一张票。剩余票数:2
窗口Thread-2售出一张票。剩余票数:1
窗口Thread-2售出一张票。剩余票数:0
没有余票!
没有余票!
没有余票!