多线程(四)-线程同步

大佬的理解-> 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张票

可以正常买票,问题解决;

标签: Java

添加新评论