先通过代码还原一下多线程并发的问题
package com.example.exception;
public class Tickets implements Runnable{
int ticket_nums=10;
@Override
public void run() {
while (true){
if(ticket_nums<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"抢到票了-->"+ticket_nums--);
}
}
public static void main(String[] args) {
Tickets tickets = new Tickets();
new Thread(tickets,"李雷").start();
new Thread(tickets,"韩梅梅").start();
new Thread(tickets,"黄牛").start();
}
}
执行后日志可以看到问题:
解决方式一@Override
public synchronized void run() {
while (true){
if(ticket_nums<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"抢到票了-->"+ticket_nums--);
}
}
在方法前面 添加 synchronized,方法同步,执行后看到日志可以发现有趣的现象,是队列+锁的机制。不建议使用这种方式,效率低。
韩梅梅抢到票了-->10 韩梅梅抢到票了-->9 韩梅梅抢到票了-->8 韩梅梅抢到票了-->7 韩梅梅抢到票了-->6 韩梅梅抢到票了-->5 韩梅梅抢到票了-->4 韩梅梅抢到票了-->3 韩梅梅抢到票了-->2 韩梅梅抢到票了-->1解决方法二
@Override
public void run() {
while (true){
// 只针对更新对象操作的地方增加同步
synchronized (this){
if(ticket_nums<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"抢到票了-->"+ticket_nums--);
}
}
}
解决方法三
JUC包中的lock,显示锁,效率更好,通过日志就可以发现,推荐使用
package com.example.exception;
import java.util.concurrent.locks.ReentrantLock;
public class Tickets implements Runnable{
int ticket_nums=10;
@Override
public void run() {
// ReentrantLock:一个可重入的互斥锁,为Lock接口的主要实现
ReentrantLock reentrantLock = new ReentrantLock();
while (true) {
try {
reentrantLock.lock();
if (ticket_nums <= 0) {
break;
}
System.out.println(Thread.currentThread().getName() + "抢到票了-->" + ticket_nums--);
} catch (Exception exception) {
exception.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
}
public static void main(String[] args) {
Tickets tickets = new Tickets();
new Thread(tickets,"李雷").start();
new Thread(tickets,"韩梅梅").start();
new Thread(tickets,"黄牛").start();
}
}



