多线程(四)-线程同步
大佬的理解-> Java多线程(三)--synchronized关键字详情
大佬的理解-> Java多线程(三)--synchronized关键字续
1、问题引入
买票问题
1.1 通过继承Thread买票
继承Thread买票案例
/*
模拟网络购票,多线程资源共享问题,继承Thread方式;
结论:此种方式,不存在资源共享,通过创建对象启动的线程,每个对象都有各自的属性值
*/
public class MyThreadTicket extends Thread{
//总票数
private int remainSite = 100;
//抢到的座位号
private int buySite = 0;
@Override
public void run() {
//模拟循环抢票
while(true){
//判断余票是否充足,如果不足,结束
if(remainSite <= 0){
break;
}
//更改强股票数据
buySite++;
remainSite--;
//模拟网络延迟
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买到第"+buySite+"张票,剩余"+remainSite+"张票");
}
}
public static void main(String[] args) {
//模拟三人同事抢票
MyThreadTicket threadTicket1 = new MyThreadTicket();
threadTicket1.setName("猪八戒");
MyThreadTicket threadTicket2 = new MyThreadTicket();
threadTicket2.setName("沙和尚");
MyThreadTicket threadTicket3 = new MyThreadTicket();
threadTicket3.setName("孙猴子");
System.out.println("---抢票开始---");
threadTicket1.start();
threadTicket2.start();
threadTicket3.start();
}
}
运行结果
---抢票开始---
猪八戒买到第1张票,剩余99张票
孙猴子买到第1张票,剩余99张票
沙和尚买到第1张票,剩余99张票
孙猴子买到第2张票,剩余98张票
猪八戒买到第2张票,剩余98张票
沙和尚买到第2张票,剩余98张票
孙猴子买到第3张票,剩余97张票
沙和尚买到第3张票,剩余97张票
猪八戒买到第3张票,剩余97张票
猪八戒买到第4张票,剩余96张票
沙和尚买到第4张票,剩余96张票
孙猴子买到第4张票,剩余96张票
孙猴子买到第5张票,剩余95张票
......
孙猴子买到第99张票,剩余1张票
猪八戒买到第99张票,剩余1张票
沙和尚买到第99张票,剩余1张票
孙猴子买到第100张票,剩余0张票
猪八戒买到第100张票,剩余0张票
沙和尚买到第100张票,剩余0张票
出现的问题
每个人都买了100张票,没有共享数据;
1.2 通过实现Runnable接口买票
实现Runnable接口案例
/*
模拟网络购票,实现Runnable方法
*/
public class MyRunnableTicket0 implements Runnable{
//总票数
private int remainSite = 100;
//抢到的座位号
private int buySite = 0;
@Override
public void run() {
//模拟循环抢票
while(true){
//判断余票是否充足,如果不足,结束
if (remainSite <= 0) {
break;
}
//更改强股票数据
buySite++;
remainSite--;
//模拟网络延迟
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买到第" + buySite + "张票,剩余" + remainSite + "张票");
}
}
public static void main(String[] args) {
//创建三个子线程
MyRunnableTicket0 runnableTicket = new MyRunnableTicket0();
Thread thread1 = new Thread(runnableTicket,"哪吒");
Thread thread2 = new Thread(runnableTicket,"金吒");
Thread thread3 = new Thread(runnableTicket,"木吒");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果
木吒买到第96张票,剩余4张票
哪吒买到第96张票,剩余4张票
金吒买到第96张票,剩余4张票
木吒买到第99张票,剩余1张票
哪吒买到第99张票,剩余1张票
金吒买到第99张票,剩余1张票
木吒买到第100张票,剩余0张票
出现的问题
共享了数据,但是出现了漏票,和几个人买同一张票的情况;
2、解决方法
通过synchronized同步锁来进行同步,使同一时间只有一个人在买票;
2.1 同步代码块
同步代码块案例
/*
模拟网络购票,实现Runnable方法
同步代码块方法
*/
public class MyRunnableTicket implements Runnable{
//总票数
private int remainSite = 100;
//抢到的座位号
private int buySite = 0;
//同步代码块
@Override
public void run() {
//模拟循环抢票
while(true){
//同步代码快
synchronized (this) {
//判断余票是否充足,如果不足,结束
if (remainSite <= 0) {
break;
}
//更改强股票数据
buySite++;
remainSite--;
//模拟网络延迟
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买到第" + buySite + "张票,剩余" + remainSite + "张票");
}
}
}
public static void main(String[] args) {
//创建三个子线程
MyRunnableTicket runnableTicket = new MyRunnableTicket();
Thread thread1 = new Thread(runnableTicket,"哪吒");
Thread thread2 = new Thread(runnableTicket,"金吒");
Thread thread3 = new Thread(runnableTicket,"木吒");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果
哪吒买到第1张票,剩余99张票
哪吒买到第2张票,剩余98张票
哪吒买到第3张票,剩余97张票
哪吒买到第4张票,剩余96张票
哪吒买到第5张票,剩余95张票
......
金吒买到第96张票,剩余4张票
金吒买到第97张票,剩余3张票
金吒买到第98张票,剩余2张票
金吒买到第99张票,剩余1张票
金吒买到第100张票,剩余0张票
可以正常买票,问题解决;
2.2 同步方法
同步方法案例
/*
模拟网络购票,实现Runnable方法
同步方法
*/
public class MyRunnableTicket implements Runnable{
//总票数
private int remainSite = 100;
//抢到的座位号
private int buySite = 0;
@Override
public void run() {
//模拟循环抢票
while(remainSite > 0){
//调用同步购买方法
buyTicket();
//模拟网络延迟
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
同步方法
增加同步锁,限制多线程场景下,只允许一个线程执行当前方法,确保票数修改正确
*/
public synchronized void buyTicket(){
//判断余票是否充足,如果不足,结束
if(remainSite <= 0){
return;
}
//更改强股票数据
buySite++;
remainSite--;
System.out.println(Thread.currentThread().getName()+"买到第"+buySite+"张票,剩余"+remainSite+"张票");
}
运行结果
哪吒买到第1张票,剩余99张票
哪吒买到第2张票,剩余98张票
哪吒买到第3张票,剩余97张票
哪吒买到第4张票,剩余96张票
哪吒买到第5张票,剩余95张票
......
金吒买到第96张票,剩余4张票
金吒买到第97张票,剩余3张票
金吒买到第98张票,剩余2张票
金吒买到第99张票,剩余1张票
可以正常买票,问题解决;