多线程(四)-线程同步
2023-06-13 09:14:10 时间
大佬的理解-> 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张票
可以正常买票,问题解决;
相关文章
- linux ntp时钟服务器地址_Linux时间同步+国内常用的NTP服务器地址【NTP时间同步服务器】…
- C++多线程编程:同步之互斥量Mutex「建议收藏」
- 同步FIFO和异步FIFO总结[通俗易懂]
- 3-多线程安全问题,线程同步
- 推荐一款 在线+离线数据 同步框架 Dotmim.Sync
- Linux基础:讲解Linux C++多线程同步的方式
- java多线程有几种实现方法线程之间如何同步详解编程语言
- 关于synchronized和ReentrantLock之多线程同步详解编程语言
- MySQL主从多线程同步:实现高效数据复制(mysql主从多线程同步)
- Java多线程的同步机制:synchronized
- 量Linux进程:利用信号量进行同步(linux进程信号)
- MySQL 数据库重新同步(mysql重新同步)
- Linux读写同步:保障数据一致性(linux读写同步)
- Oracle主从同步高效稳定的数据同步解决方案(Oracle主从工具)
- 多线程优化高效同步写入Redis(多线程向redis写数据)
- 多线程同步更新重塑Redis数据(多线程修改redis数据)
- Oracle 信号量实现安全多对多多线程同步 (oracle 信号量)
- 实现Redis集群数据同步的策略(redis集群的数据同步)
- 异地实现Redis集群数据同步(redis集群异地同步)
- c#.net多线程编程教学——线程同步
- 使用Barrier来控制线程同步示例
- Python多线程同步Lock、RLock、Semaphore、Event实例
- C#简单多线程同步和优先权用法实例