Java多线程机制

一、实验目的及要求

(1)实验目的:学习使用Thread子类或者Runnable接口创建多线程,实现线程同步机制。

(2)实验要求:两个或者多个线程同时访问同一个变量时,不允许发生数据读取错误,产生数据不一致的情形,要求对实验中出现的数据问题进行分析,确定调试步骤和测试方法,对实验结果进行总结。

二、实验环境(工具、配置等)

1.硬件要求:计算机一台。

2.软件要求:Windows操作系统,使用Java语言,集成开发环境建议使用如Eclipse

三、实验内容(实验方案、实验步骤、设计思路等)

1.实验方案:实验中,编写多线程程序,模拟两个或者多个线程同时访问同一个变量时,并且一个线程需要修改这个变量,需要对这样的问题进行处理,把修改数据的方法用关键字synchronized修饰,否则可能发生数据错误,从而实现线程同步目的,完成实验报告。

2.实验步骤:根据教材和老师课堂的讲解。

1创建两个类:Test主类和Warehouse仓库类

2)Test主类中通过Thread 类创建三个线程对象,将Runnable接口的子类对象warehouse作为实际参数传递给Thread类的构造函数,并调用启动入仓库into、清点仓库check、出仓库out三个线程,设定仓库货物初始值。

3)Warehouse仓库类中实现Runnable接口,设置设定修改货物初始值的方法setcargo(),设置同步方法inOrcheckOrout(),在这个方法中实现三个线程分别对仓库的访问和对cargo变量的访问使用和修改,在run()方法中根据线程名字分别调用该同步方法,传入不同的参数。

3.设计思路:

在这个程序中一共有三个线程,即入仓库、清点仓库和出仓库。入仓库、清点仓库和出仓库共同拥有一个仓库,他们都可以使用inOrcheckOrout(int number)方法通过if else if语句对应的对仓库进行访问,if else if语句中通过str.equals()方法来识别是哪个线程。入仓库使用inOrcheckOrout(int number)方法向仓库存入货物;清点仓库使用inOrcheckOrout(int number)方法对仓库的货物进行清点,这个时候需要在清点线程中累加清点货物的数量,然后将这个累计数量赋值给全局变量cargo,为了让出仓库的线程使用;出仓库使用inOrcheckOrout(int number)方法从仓库取出已经清点过的货物。在三个线程访问仓库的时候,设置了分段的工作和休息时间(sleep()方法的使用),但是在休息时间的时候仓库也是归这个线程进行使用的。这三个线程任意一个正在使用inOrcheckOrout(int number)方法的时候,其余两个线程是被禁止使用的,所以inOrcheckOrout(int number)方法是一个synchronized方法。最后在Test主类中调用启动这三个线程。

  • 实验结果与分析
  1. 运行结果如图4-1所示:

  

图4-1 屏幕输出结果

实验分析:

1.实验遇到的问题:

1)在计算未清点的货物或者计算未出库的货物的时候,如果直接用cargo(总量)减去checkcargo(已清点)或者cargo减去outcargo(已出库)时,屏幕输出的时候会输出负数。

2.问题解决的方法:

1)因为在inOrcheckOrout(int number)这个方法里,每一个线程对仓库的访问是根据仓库货物总量cargo的大小,对传入的参数number进行分割,作为清点或者出库的货物的数量,那么当这个number比较大,会造成checkcargo和outcargo大于cargo的情况,那这个时候肯定是最多清点或者出库了cargo数量的情况,所以用Math.min()方法来确保清点和出库的数量,确保不会有负数情况的出现。

  • 附源程序
  • Test类:
    package shiyanbaogao_eight;
    
    public class Test{
    	public static void main(String args[]) {
    		Warehouse warehouse=new Warehouse();
    		warehouse.setcargo(200);// 仓库货物初始值 200
    		Thread into,//入仓库
    		       check,//清点仓库
    		       out;//出货物
    		into =new Thread(warehouse);
    		check=new Thread(warehouse);
    		out=new Thread(warehouse);
    		into.setName("入仓库");
    		check.setName("清点仓库");
    		out.setName("出仓库");
    		into.start();//启动线程
    		try {
    			Thread.sleep(1000);
    		} catch (Exception e) {
    			// TODO: handle exception  
    			e.printStackTrace();
    		}
    		out.start();//启动线程
    		try {
    			Thread.sleep(1000);
    		} catch (Exception e) {
    			// TODO: handle exception  
    			e.printStackTrace();
    		}
    		check.start();//启动线程
    	}
    }
    Warehouse类:
    package shiyanbaogao_eight;
    
    import java.time.chrono.MinguoChronology;
    
    public class Warehouse implements Runnable{
    	int cargo=100;//设置货物初始值是100
    	//设置函数 可以修改货物的值
    	public void setcargo(int m) {
    		// TODO Auto-generated method stub
    		cargo=m;
    	}
    	public void run() {
    		if(Thread.currentThread().getName().equals("入仓库"))//入仓库120货物
    		{
    			inOrcheckOrout(120);
    		}
    		if(Thread.currentThread().getName().equals("清点仓库"))//清点110货物
    		{
    			inOrcheckOrout(110);
    		}
    		if(Thread.currentThread().getName().equals("出仓库"))//出仓库100货物
    		{
    			inOrcheckOrout(100);
    		}
    	}
    	 //设置同步方法 入或清点或出 inOrcheckOrout
    		public synchronized void inOrcheckOrout(int number) {
    			if(Thread.currentThread().getName().equals("入仓库")) {
    				for(int i=0;i<4;i++)//分4次入仓库
    				{
    					cargo=cargo+number/4;// 每次30件入仓库
    					System.out.println(Thread.currentThread().getName()+
    							"入了"+number/4+"货物到仓库,目前仓库货物总量:"+cargo+"件,休息一下再入");
    					try {
    						Thread.sleep(1000);// 当前线程休眠1s
    					} catch (InterruptedException e) {
    						// TODO: handle exception
    						e.printStackTrace();
    					}
    				}
    			}
    			else if(Thread.currentThread().getName().equals("清点仓库")) {
    				int checkcargo=0;//初始清点货物量为0
    				int checkcargosum=0;//设置清点货物总量
    				for(int i=0;i<4;i++)//设置四次循环
    				{
    					//下面根据仓库货物总量进行清点
    					if(cargo>=250)
    					{
    						checkcargo=number/2;
    					}
    					else if(cargo >= 100 && cargo < 250)
    					{
    						checkcargo=number/4;
    					}
    					else if(cargo>= 50 && cargo < 100)
    					{
    						checkcargo=number/5;
    					}
    					else if(cargo>=0 && cargo<50){
    						checkcargo=number/10;
    					}
    					// 这里的货物代表的是 还没有进行清点的 
    					// 这里减掉的是这俩之间的最小值 是因为要么清点的比总量少 要么清点的和总量一样多
    					cargo=cargo-Math.min(cargo, checkcargo);//调用java.lang.Math中的min()函数
    					System.out.println(Thread.currentThread().getName()+
    							"清点了"+Math.min(checkcargo, cargo)+"件货物,还有"+cargo+"件未清点,休息一下再清点");
    					checkcargosum+=Math.min(cargo,checkcargo);//累加已经清点了的量
    					try {
    						Thread.sleep(1000);// 当前线程休眠1s
    					} catch (InterruptedException e) {
    						// TODO: handle exception
    						e.printStackTrace();
    					}
    				}
    				cargo=checkcargosum;//让此时 仓库总量变为已经清点了的量 用来出库
    			}
    			else {//出仓库
    				for(int i=0;i<4;i++)//设置四次循环
    				{
    					int outcargo=0;//初始清点货物量为0
    					//下面根据仓库已清点货物总量进行出库
    					if(cargo>=250)
    					{
    						outcargo=number/2;
    					}
    					else if(cargo >= 100 && cargo < 250)
    					{
    						outcargo=number/4;
    					}
    					else if(cargo>= 50 && cargo < 100)
    					{
    						outcargo=number/5;
    					}
    					else if(cargo>=0 && cargo<50){
    						outcargo=number/10;
    					}
    					// 这里的货物代表的是 还没有进行清点的 
    					// 这里减掉的是这俩之间的最小值 是因为要么出库的比清点的少 要么清点的和出库的一样多
    					cargo=cargo-Math.min(cargo, outcargo);//调用java.lang.Math中的min()函数
    					System.out.println(Thread.currentThread().getName()+
    							"出库了"+Math.min(outcargo, cargo)+"件货物,还有"+cargo+"件未出库,休息一下再出库");
    					try {
    						Thread.sleep(1000);// 当前线程休眠1s
    					} catch (InterruptedException e) {
    						// TODO: handle exception
    						e.printStackTrace();
    					}
    				}
    			}
    		}
    	}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cwn_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值