线程同步问题

使用 Linux 系统提供的线程同步 API 解决线程同步问题 一、用信号量完成四个线程的同步。主程序创建四个线程,其中两个线程负责 从文件读取数据到公共缓冲区,另两个线程从缓冲区读取数据分别做加、乘运算。 运行程序之前先编辑好数据文件 file1.dat 和 file2.dat,分别输入 1 2 3 4 5 6 7 8 9 10 和-1 -2 -3 -4 -5 -6 -7 -8 -9 -10。 阅读详情

在此之前我先给出这样一个情景:
锅里有一个饼,有两个饥饿的人同时看到了这个饼,按理来说,只有一个人能够吃到饼,那如果我们把饼看作一个信息,饥饿的人看作两个线程,会发生什么?

package com.Test;

public class Cookies_and_hugry_people extends Thread {
	
	int cookies_num = 1;//表示一块饼
	public void run() {
		
		System.out.println(Thread.currentThread().getName()+"来了");
		
			System.out.println("桌上有" + cookies_num + "块饼");
			if(cookies_num != 0) {
				System.out.println(Thread.currentThread().getName()+"想吃饼");
				cookies_num--;
				System.out.println(Thread.currentThread().getName() + "吃掉一块饼,还剩" + cookies_num + "块饼");

			}
			
		
	}

	public static void main(String[] args) {
		Cookies_and_hugry_people obj = new Cookies_and_hugry_people();
		new Thread(obj,"小明").start();
		new Thread(obj,"小刚").start();
	}
}

结果输出为这样
在这里插入图片描述
还剩-1块饼?!
显然,两个线程共用了桌上有1块饼的信息最后竟然无中生有暗度陈仓,这显然不是我们希望看到的结果。所以我们可以想办法让一个线程进行完以后再让另一个线程去执行代码

只需要给代码块加上锁就好了

public void run() {

		System.out.println(Thread.currentThread().getName() + "来了");
		synchronized (this) {//新加代码,给该部分上锁

			System.out.println("桌上有" + cookies_num + "块饼");
			if (cookies_num != 0) {
				System.out.println(Thread.currentThread().getName() + "想吃饼");
				cookies_num--;
				System.out.println(Thread.currentThread().getName() + "吃掉一块饼,还剩" + cookies_num + "块饼");

			}
		}

	}

其运行结果为
在这里插入图片描述

synchronized 字面意思为同步,其后面的括号里为一个对象,即对括号中的对象上锁,在一个线程中,这个对象进入代码块就相当于上了锁,必须等其运行完整个代码后才解锁,让另一个线程对象进来。

生产者消费者模式
先在我们再次假设一个情景,有一个生产饼干的机器,能够源源不断地生产出饼干来,放到桌上,并且能够判断桌上是不是放满了饼,如果桌上放不下了,机器就会停止生产(生产者);然后有饥饿的人,只要桌上有饼就会吃掉饼(消费者)。

package com.Test_producer_and_consumer;

import java.util.ArrayList;

public class Producers extends Thread{
	ArrayList<String> cookies=new ArrayList<>();
	public Producers(ArrayList<String> cookies) {
		this.cookies=cookies;
	}
	public void run() {
		System.out.println("机器准备就绪~~~");
		while(true) {
			
				try {
					synchronized (cookies) {
					Thread.sleep(1000);

					if(cookies.size()<3) {
						cookies.add("饼"+cookies.size());
						System.out.println("机器生产了一个饼,现在有"+cookies.size()+"个饼");
						cookies.notify();
					}
					if(cookies.size()==3) {
						System.out.println("桌上装不下饼了,机器停止生产");
						cookies.wait();
					}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

将饼装在**ArrayList**队列里面。互斥对象为cookies,当桌上装满了饼则会呼叫饥饿的小明过来吃饼

package com.Test_producer_and_consumer;

import java.util.ArrayList;

public class Resumer extends Thread{
	ArrayList<String> cookies =new ArrayList<>();
	public Resumer(ArrayList<String> cookies) {
		this.cookies=cookies;
	}
	public void run () {
		System.out.println("饥饿的小明准备就绪~~~~");
		while(true) {
			synchronized (cookies) {
				try {
					Thread.sleep(1000);
					if(cookies.size()>0) {
						cookies.remove(0);
						System.out.println("小明吃掉了一个饼,现在有"+cookies.size()+"个饼,又可以叫机器做饼了,呼叫机器");
						
						cookies.notify();
					}
					if(cookies.size()==0) {
						System.out.println("桌上的饼吃光了,小明停止吃饼");
						cookies.wait();
					}
					
					
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

然后将两个线程同时启动

package com.Test_producer_and_consumer;

import java.util.ArrayList;

public class Main {
	public static void main(String[] args) {
		ArrayList<String> cookies=new ArrayList<>();
		new Producers(cookies).start();
		new Resumer(cookies).start();
	}
}

运行结果如下
在这里插入图片描述
我们可以看到,小明吃了饼以后需要开始呼叫机器,但由于此时程序并没有结束小明不会停止吃饼只有等到饼吃完以后,小明停止吃饼了,机器才能进入自己的代码块,也就是说关于cookies对象的代码块被锁住了
如果我们在生产一个饼之后机器就停下来就会出现这样的情况:

package com.Test_producer_and_consumer;

import java.util.ArrayList;

public class Producers extends Thread{
	ArrayList<String> cookies=new ArrayList<>();
	public Producers(ArrayList<String> cookies) {
		this.cookies=cookies;
	}
	public void run() {
		System.out.println("机器准备就绪~~~");
		while(true) {
			
				try {
					synchronized (cookies) {
					Thread.sleep(1000);

					if(cookies.size()<3) {
						cookies.add("饼"+cookies.size());
						System.out.println("机器生产了一个饼,现在有"+cookies.size()+"个饼");
						cookies.notify();
						cookies.wait();
					}
					if(cookies.size()==3) {
						System.out.println("桌上装不下饼了,机器停止生产");
//						cookies.wait();
					}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

对比之前的Producers类,机器在生产一个饼之后就开始wait了。
在这里插入图片描述

Java中多线程同步问题的解决方法 Java中的多线程同步问题是一个复杂的问题,但通过使用上述的多种方法,可以有效地解决这些问题。在实际开发中,应根据具体的需求和场景选择合适的同步方法。例如,对于简单的同步需求,可以使用关键字;对于需要更灵活锁机制的场景,可以使用;对于需要控制线程访问资源数量的场景,可以使用Semaphore等。同时,还应注意避免过度同步,以免影响程序的性能。希望本文的内容能够帮助读者更好地理解和解决Java多线程同步问题。 阅读详情

相关推荐

ST7789驱动实战:从SPI时序到RGB565显示的完整配置解析

本文详细解析了ST7789液晶驱动芯片的SPI时序配置与RGB565显示实现,从数据手册解读到代码实战,涵盖SPI接口配置、关键寄存器设置及完整初始化流程。通过优化DMA传输和常见问题排查,帮助开发者高效驱动ST7789显示屏,适用于嵌入式显示项目开发。

weixin_29162439的博客 184

线程同步的经典问题

当哲学家 1 和哲学家 2 抢到各自左手边的筷子后,同时需要右手边的筷子,但此时右手边的筷子已被哲学家 2 和哲学家 3 已经拿起,等待哲学家 2 和哲学家 3 放下右边筷子后,哲学家 1 和哲学家 2 才能拿到右手边的筷子,才能进餐。线程同步还可以提高程序的执行效率,对于频繁访问共享资源的应用,如果没有线程同步机制,可能会出现一些性能问题,例如资源等待、线程竞争等等。总之,生产者消费者问题是一个经典的线程同步问题。此时,让哲学家先使用右边的筷子,再使用左边的筷子,吃完面条之后,把这两个筷子放回原处。

weixin_46326585的博客 922

电力市场小白必看:手把手教你用Matlab实现市场出清电价计算(附完整代码)

本文为电力市场初学者提供了使用Matlab计算市场出清电价的完整指南。通过Yalmip和Matpower工具包,详细讲解了从环境配置到模型构建、求解及结果分析的整个过程,帮助读者快速掌握节点电价计算的核心技术。

weixin_30379531的博客 74

线程同步(一)

线程同步的概念及线程同步方式

好好学习,天天向上 2801

STM32 FATFS文件系统按行读取SD卡数据

STM32 SD数据实现按行读取

qq_32216815的博客 7828

电芯外观及体系设计(Cell Design)-①容量平衡设计(Cell Balance Design)

全面获取并正确解读客户需求,将需求进行分解和预判,结合公司现有资源、技术,给出设计方案。一个优秀的电芯设计方案,应该是稳健的,可操作的,满足客户需求的同时,并能为公司带来较多利润。电芯设计需同时考虑周期,性能,品质,加工性,成本,及安全与稳健性。设计人员时刻要有成本控制观念,但利润则是由公司战略所决定。

FDC1303864002的博客 1353

线程中的同步机制问题(三种解决方法)

线程的同步机制(三种解决方法),synchronized中的同步代码块、同步方法以及lock锁机制。

咸鱼老潘的编码生活 1935

”COMSOL“竟然如此简单!我悟了!!

COMSOL Multiphysics具有强大的多物理场全耦合仿真分析功能、高效的计算性能,可以保证数值仿真的高度精确,已被广泛应用于各个学科领域,近年来运用COMSOL来解决电化学实际工程问题也越来越普遍。

C1012562281的博客 3449

【Java学习】多线程-线程同步方案&线程池

线程同步就是让多个线程实现先后依次访问共享资源,这样就解决了安全问题,它最常见的方案就是加锁加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来线程池就是一个可以复用线程的技术它就像一个大的池子一样,里面可以放置一些线程,当需要的时候,就从里面取出来用,用完了就还回去如此一来,就不必频繁的创建和销毁线程了,大大的提高了线程的利用率,提供系统的性能1、任务进入线程池,先看核心线程是否满了,如果没满则创建新的核心线程。

weixin_69134024的博客 1408

机器学习系列(1)_逻辑回归初步

1、总述 逻辑回归是应用非常广泛的一个分类机器学习算法,它将数据拟合到一个logit函数(或者叫做logistic函数)中,从而能够完成对事件发生的概率进行预测。 2、由来     要说逻辑回归,我们得追溯到线性回归,想必大家对线性回归都有一定的了解,即对于多维空间中存在的样本点,我们用特征的线性组合去拟合空间中点的分布和轨迹。如下图所示:     线性回归能对连续值结果进行预测,

寒小阳 13万+

基于Python的股票K线图爬取与形态识别系统

本文详细介绍了一个基于Python的股票K线图爬取与形态识别系统。该系统通过网络爬虫技术获取股票历史数据,使用Matplotlib生成K线图,并应用卷积神经网络(CNN)对经典K线形态进行识别。文章详细阐述了数据采集、K线图生成、CNN模型构建与训练的完整流程,并提供了完整的代码实现。本研究为金融科技领域的毕业设计提供了有价值的参考方案。关键词:Python爬虫、K线图、卷积神经网络、形态识别、股票交易。

2201_76125261的博客 1033

Java并发编程精讲

课程会讲解Java中并发相关技术的基础、原理和应用,从线程安全、线程(池),锁实现和并发容器等高并发Java实现,去深入理解在并发编程中,一些最容易被忽视的点,这些点也是我在多年编程经验中实际用到,对于每个小节小课均会有实际的场景应用为你呈现。同时这些也是面试过程中面试官考察的重点,掌握这些点,面试和工作时,做到心中有货,不慌不乱,能够胜任。

092、Python在芯片验证中的应用:从脚本小子到验证架构师

Python在芯片验证中的高效应用 本文通过实际案例展示了Python在芯片验证中的关键作用。凌晨三点的调试场景揭示了传统方法的局限,Python脚本能在20分钟内分析80GB波形数据定位FIFO指针问题。文章重点介绍了两个核心工具: 智能日志分析系统:通过正则表达式和上下文分析,自动分类百万行验证日志中的错误,生成可视化报告,效率远超传统grep方法。 寄存器模型生成器:将Excel表格自动转换为UVM寄存器模型代码,将原本需要两周的手工工作缩短至两小时,同时保证零错误。 文章还展示了Python与Sys

z534437748的博客 73

线程安全,线程同步,解决线程同步问题

线程安全,线程同步,解决线程同步问题,synchronized,同步代码块,同步方法

weixin_46140377的博客 884

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java多线程 - 线程安全和线程同步解决线程安全问题

线程安全问题。

dzqxwzoe的博客 978

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

深入解析线程同步中WaitForSingleObject的超时问题

线程同步要考虑操作系统调度特性WaitForSingleObject的参数是"最大等待"而非"检测间隔"完善的错误恢复机制至关重要动态调整等待时间可以提高系统健壮性希望这篇分析能帮助遇到类似问题的开发者。良好的线程同步设计就像交通信号灯,需要合理的"等待时间"设置才能保证系统流畅运行。

码事漫谈 1291

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

二、多线程同步问题

一、线程安全问题 比如同一个账户,加入父亲和儿子同时在不同的窗口同时取钱,比如剩余1000块,父亲取了800,儿子也取了800,不同窗口没有及时同步数据,可能就会实际支出了1600,而这是不允许发生的; - 这种不安全的问题并不是一定会发生,取决于线程的具体调度; - 但是一旦发生,就是灾难性的,必须在代码层面解决; 账户类 public class Account { private double balance; private String name; // set及get及有

weixin_43374578的博客 3484

[java多线程]的同步问题

指的是多个线程同时修改一个过程时,可能导致的问题 引入: 以卖票问题为例:假设总共有十张票,三个黄牛卖票(代表三个子线程),预测最后一个黄牛卖完票,还剩下0张票 package se.SE.practice; class MyThread implements Runnable { private int ticket=10; @Override public vo...

weixin_42645168的博客 234

线程同步问题的引出

假设现在有一个卖票的情景,票数是固定的,正常情况下每当一个人买完n张票,票数就减少n张,然后直到票数为0为止。下面我们简单的模拟该情景: class TickectThread implements Runnable{ private int tickect = 5; @Override public void run() { for(int i = 0; i < 1...

写写代码 203

Java的线程同步和并发问题示例

并发问题 多线程是一个非常强大的工具,它使我们能够更好地利用系统的资源,但我们需要在读取和写入多个线程共享的数据时特别小心。 当多个线程尝试同时读取和写入共享数据时,会出现两种类型的问题 - 线程干扰错误内存一致性错误让我们逐一理解这些问题。 线程干扰错误(竞争条件) 考虑以下Cou...

cheyun0833的博客 396

线程安全问题 线程同步

线程安全问题,同步1.线程安全问题1.1.什么是线程安全1.2.问题演示1.2.1.第一步:创建售票线程类1.2.2.第二步:创建测试类1.3.问题分析1.4.问题解决-线程同步1.4.1.同步代码块(synchronized)1.4.2.同步方法(synchronized)1.4.3.同步锁(ReenreantLock)标题1.5.小结 哔哩哔哩大神的视频整理 1.线程安全问题 1.1.什么是线程安全 如果有多个线程同时运行同一个实现了Runnable接口的类,程序每次运行结果和单线程运行的结果是一样的,

weixin_45229007的博客 404

java Android 中关于线程同步问题

Java 两个线程间的通信

u012288123的专栏 3059
上一篇: 线程起步,解决一个过程只能进行一次画图的问题
下一篇: 彻底解决java传参问题
南懿烨曦
博客等级 码龄6年 108粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值