单线程、多线程以及线程安全个人理解

在这里,我不对多线程原理在做阐述。想了解的读者可以参考:

https://blog.csdn.net/douglax/article/details/1532258

这里,我将抽象的概念具体化,通过和尚挑水的故事对多线程做解释。

1、首先定义和尚类Monk

package com.stu.thread;

/**
 * 和尚类
 * @author jj
 *
 */
public class Monk {
	private String name;
	/**
	 * 剩余需要挑的桶数<br/>
	 * 设计为静态属性(属于类的属性)。换言之,不管多少个和尚来挑水,只要挑够100桶水就够了
	 */
	public static int surplusPail = 100;
	public Monk() {
		super();
	}
	public Monk(String name) {
		super();
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * 挑水方法
	 */
	public void drawingWater(){
		if(surplusPail==100){
			System.out.println("开始挑水");
			surplusPail--;
		}else if(surplusPail<100 && surplusPail>0){
			System.out.println(this.name+"还需要挑"+surplusPail+"桶水");
			surplusPail--;
		}else if(surplusPail==0){
			System.out.println("水挑完了");
		}
	}
}

2、单线程情况下即只有一个和尚来挑水

package com.stu.thread;

import org.junit.Test;

/**
 * 单线程
 * 一个和尚(线程)挑水
 * @author jj
 *
 */
public class SigleThread {
	
	@Test
	public void sigleDrawingWater(){
		//总共需要挑100桶水
		Monk monk = new Monk("张和尚");
		while(true){
			monk.drawingWater();
			if(Monk.surplusPail<0){
				break;
			}
		}
	}
}

3、运行结果如下:

开始挑水
张和尚还需要挑99桶水
张和尚还需要挑98桶水
张和尚还需要挑97桶水
张和尚还需要挑96桶水
张和尚还需要挑95桶水
张和尚还需要挑94桶水
张和尚还需要挑93桶水
张和尚还需要挑92桶水
张和尚还需要挑91桶水
张和尚还需要挑90桶水
张和尚还需要挑89桶水
张和尚还需要挑88桶水
张和尚还需要挑87桶水
张和尚还需要挑86桶水
张和尚还需要挑85桶水
张和尚还需要挑84桶水
张和尚还需要挑83桶水
张和尚还需要挑82桶水
张和尚还需要挑81桶水
张和尚还需要挑80桶水
张和尚还需要挑79桶水
张和尚还需要挑78桶水
张和尚还需要挑77桶水
张和尚还需要挑76桶水
张和尚还需要挑75桶水
张和尚还需要挑74桶水
张和尚还需要挑73桶水
张和尚还需要挑72桶水
张和尚还需要挑71桶水
张和尚还需要挑70桶水
张和尚还需要挑69桶水
张和尚还需要挑68桶水
张和尚还需要挑67桶水
张和尚还需要挑66桶水
张和尚还需要挑65桶水
张和尚还需要挑64桶水
张和尚还需要挑63桶水
张和尚还需要挑62桶水
张和尚还需要挑61桶水
张和尚还需要挑60桶水
张和尚还需要挑59桶水
张和尚还需要挑58桶水
张和尚还需要挑57桶水
张和尚还需要挑56桶水
张和尚还需要挑55桶水
张和尚还需要挑54桶水
张和尚还需要挑53桶水
张和尚还需要挑52桶水
张和尚还需要挑51桶水
张和尚还需要挑50桶水
张和尚还需要挑49桶水
张和尚还需要挑48桶水
张和尚还需要挑47桶水
张和尚还需要挑46桶水
张和尚还需要挑45桶水
张和尚还需要挑44桶水
张和尚还需要挑43桶水
张和尚还需要挑42桶水
张和尚还需要挑41桶水
张和尚还需要挑40桶水
张和尚还需要挑39桶水
张和尚还需要挑38桶水
张和尚还需要挑37桶水
张和尚还需要挑36桶水
张和尚还需要挑35桶水
张和尚还需要挑34桶水
张和尚还需要挑33桶水
张和尚还需要挑32桶水
张和尚还需要挑31桶水
张和尚还需要挑30桶水
张和尚还需要挑29桶水
张和尚还需要挑28桶水
张和尚还需要挑27桶水
张和尚还需要挑26桶水
张和尚还需要挑25桶水
张和尚还需要挑24桶水
张和尚还需要挑23桶水
张和尚还需要挑22桶水
张和尚还需要挑21桶水
张和尚还需要挑20桶水
张和尚还需要挑19桶水
张和尚还需要挑18桶水
张和尚还需要挑17桶水
张和尚还需要挑16桶水
张和尚还需要挑15桶水
张和尚还需要挑14桶水
张和尚还需要挑13桶水
张和尚还需要挑12桶水
张和尚还需要挑11桶水
张和尚还需要挑10桶水
张和尚还需要挑9桶水
张和尚还需要挑8桶水
张和尚还需要挑7桶水
张和尚还需要挑6桶水
张和尚还需要挑5桶水
张和尚还需要挑4桶水
张和尚还需要挑3桶水
张和尚还需要挑2桶水
张和尚还需要挑1桶水
水挑完了

****单线程:对于单线程的情况不必做过多解释

4、两个和尚一起挑水(多线程情况)

/**
 * 多线程
 * 许多和尚一起挑水
 * @author jj
 *
 */
public class ManyThread {
	
	/**
	 * 两个和尚一起来
	 * @param args
	 */
	public static void main(String[] args) {
		Monk monk = new Monk("张和尚");
		Monk monk1 = new Monk("李和尚");
		DrawingWater d = new DrawingWater(monk);
		DrawingWater d1 = new DrawingWater(monk1);
		new Thread(d).start();
		new Thread(d1).start();
	}
	
//	@Test
//	public void main(){
//		Monk monk = new Monk("张和尚");
//		DrawingWater d = new DrawingWater(monk);
//		new Thread(d).start();
//	}
}

5、将挑水的操作设计为线程

/**
 * 线程类
 * @author jj
 *
 */
class DrawingWater implements Runnable{
	private Monk monk;
	
	public DrawingWater(Monk monk) {
		super();
		this.monk = monk;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			monk.drawingWater();
			if(Monk.surplusPail<=0){
				break;
			}
		}
	}
	
}

运行结果:

开始挑水
开始挑水
张和尚还需要挑99桶水
李和尚还需要挑98桶水
李和尚还需要挑97桶水
李和尚还需要挑96桶水
李和尚还需要挑95桶水
李和尚还需要挑94桶水
李和尚还需要挑93桶水
李和尚还需要挑92桶水
李和尚还需要挑91桶水
李和尚还需要挑90桶水
李和尚还需要挑89桶水
李和尚还需要挑88桶水
李和尚还需要挑87桶水
李和尚还需要挑86桶水
李和尚还需要挑85桶水
李和尚还需要挑84桶水
李和尚还需要挑83桶水
李和尚还需要挑82桶水
李和尚还需要挑81桶水
李和尚还需要挑80桶水
李和尚还需要挑79桶水
李和尚还需要挑78桶水
李和尚还需要挑77桶水
李和尚还需要挑76桶水
李和尚还需要挑75桶水
李和尚还需要挑74桶水
李和尚还需要挑73桶水
李和尚还需要挑72桶水
李和尚还需要挑71桶水
李和尚还需要挑70桶水
李和尚还需要挑69桶水
李和尚还需要挑67桶水
李和尚还需要挑66桶水
李和尚还需要挑65桶水
李和尚还需要挑64桶水
李和尚还需要挑63桶水
李和尚还需要挑62桶水
李和尚还需要挑61桶水
李和尚还需要挑60桶水
李和尚还需要挑59桶水
李和尚还需要挑58桶水
李和尚还需要挑57桶水
李和尚还需要挑56桶水
李和尚还需要挑55桶水
李和尚还需要挑54桶水
李和尚还需要挑53桶水
李和尚还需要挑52桶水
李和尚还需要挑51桶水
李和尚还需要挑50桶水
李和尚还需要挑49桶水
李和尚还需要挑48桶水
李和尚还需要挑47桶水
李和尚还需要挑46桶水
李和尚还需要挑45桶水
李和尚还需要挑44桶水
李和尚还需要挑43桶水
李和尚还需要挑42桶水
李和尚还需要挑41桶水
李和尚还需要挑40桶水
李和尚还需要挑39桶水
张和尚还需要挑56桶水
张和尚还需要挑37桶水
张和尚还需要挑36桶水
张和尚还需要挑35桶水
张和尚还需要挑34桶水
张和尚还需要挑33桶水
张和尚还需要挑32桶水
张和尚还需要挑31桶水
张和尚还需要挑30桶水
张和尚还需要挑29桶水
张和尚还需要挑28桶水
张和尚还需要挑27桶水
张和尚还需要挑26桶水
张和尚还需要挑25桶水
张和尚还需要挑24桶水
张和尚还需要挑23桶水
张和尚还需要挑22桶水
张和尚还需要挑21桶水
张和尚还需要挑20桶水
张和尚还需要挑19桶水
张和尚还需要挑18桶水
张和尚还需要挑17桶水
张和尚还需要挑16桶水
张和尚还需要挑15桶水
张和尚还需要挑14桶水
张和尚还需要挑13桶水
张和尚还需要挑12桶水
张和尚还需要挑11桶水
张和尚还需要挑10桶水
张和尚还需要挑9桶水
张和尚还需要挑8桶水
张和尚还需要挑7桶水
张和尚还需要挑6桶水
张和尚还需要挑5桶水
张和尚还需要挑4桶水
张和尚还需要挑3桶水
张和尚还需要挑2桶水
张和尚还需要挑1桶水
水挑完了

李和尚还需要挑38桶水

多线程:可以看见张和尚和李和尚两个和尚(线程)之间并不知道彼此挑水的情况,自己挑自己的,导致结果非常糟。这里虽然实现了多线程,但明显结果和我们预期的相差甚远,即我们常说的线程不安全。那么如何实现线程安全呢?

我们对Monk类中的drawingWater方法做调整:

package com.stu.thread;

/**
 * 和尚类
 * @author jj
 *
 */
public class Monk {
	private String name;
	/**
	 * 剩余需要挑的桶数<br/>
	 * 设计为静态属性(属于类的属性)。换言之,不管多少个和尚来挑水,只要挑够100桶水就够了
	 */
	public static int surplusPail = 100;
	
	/**
	 * 创建一个静态的对象lock,注意必须是静态的对象
	 */
	private static byte[] lock = new byte[0];
	public Monk() {
		super();
	}
	public Monk(String name) {
		super();
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * 挑水方法
	 */
	public void drawingWater(){
		/**
		 * 利用synchronized关键字实现挑水方法的同步,保证同时只能有一个和尚在挑水
		 */
		synchronized(lock){
			if(surplusPail==100){
				System.out.println("开始挑水");
				surplusPail--;
			}else if(surplusPail<100 && surplusPail>0){
				System.out.println(this.name+"还需要挑"+surplusPail+"桶水");
				surplusPail--;
			}else if(surplusPail==0){
				System.out.println("水挑完了");
				surplusPail--;
			}
		}
	}
}

在执行步骤4的操作,执行结果如下:

开始挑水
张和尚还需要挑99桶水
张和尚还需要挑98桶水
张和尚还需要挑97桶水
张和尚还需要挑96桶水
张和尚还需要挑95桶水
李和尚还需要挑94桶水
李和尚还需要挑93桶水
李和尚还需要挑92桶水
李和尚还需要挑91桶水
李和尚还需要挑90桶水
李和尚还需要挑89桶水
李和尚还需要挑88桶水
李和尚还需要挑87桶水
李和尚还需要挑86桶水
李和尚还需要挑85桶水
李和尚还需要挑84桶水
李和尚还需要挑83桶水
李和尚还需要挑82桶水
李和尚还需要挑81桶水
李和尚还需要挑80桶水
李和尚还需要挑79桶水
李和尚还需要挑78桶水
李和尚还需要挑77桶水
李和尚还需要挑76桶水
李和尚还需要挑75桶水
李和尚还需要挑74桶水
李和尚还需要挑73桶水
李和尚还需要挑72桶水
李和尚还需要挑71桶水
李和尚还需要挑70桶水
李和尚还需要挑69桶水
李和尚还需要挑68桶水
李和尚还需要挑67桶水
李和尚还需要挑66桶水
李和尚还需要挑65桶水
李和尚还需要挑64桶水
李和尚还需要挑63桶水
李和尚还需要挑62桶水
李和尚还需要挑61桶水
李和尚还需要挑60桶水
李和尚还需要挑59桶水
李和尚还需要挑58桶水
李和尚还需要挑57桶水
李和尚还需要挑56桶水
李和尚还需要挑55桶水
李和尚还需要挑54桶水
李和尚还需要挑53桶水
李和尚还需要挑52桶水
李和尚还需要挑51桶水
李和尚还需要挑50桶水
李和尚还需要挑49桶水
李和尚还需要挑48桶水
李和尚还需要挑47桶水
李和尚还需要挑46桶水
李和尚还需要挑45桶水
李和尚还需要挑44桶水
李和尚还需要挑43桶水
李和尚还需要挑42桶水
李和尚还需要挑41桶水
李和尚还需要挑40桶水
李和尚还需要挑39桶水
李和尚还需要挑38桶水
李和尚还需要挑37桶水
李和尚还需要挑36桶水
李和尚还需要挑35桶水
李和尚还需要挑34桶水
李和尚还需要挑33桶水
李和尚还需要挑32桶水
李和尚还需要挑31桶水
李和尚还需要挑30桶水
李和尚还需要挑29桶水
李和尚还需要挑28桶水
李和尚还需要挑27桶水
李和尚还需要挑26桶水
李和尚还需要挑25桶水
李和尚还需要挑24桶水
李和尚还需要挑23桶水
李和尚还需要挑22桶水
李和尚还需要挑21桶水
李和尚还需要挑20桶水
李和尚还需要挑19桶水
李和尚还需要挑18桶水
李和尚还需要挑17桶水
李和尚还需要挑16桶水
李和尚还需要挑15桶水
李和尚还需要挑14桶水
李和尚还需要挑13桶水
李和尚还需要挑12桶水
李和尚还需要挑11桶水
李和尚还需要挑10桶水
李和尚还需要挑9桶水
李和尚还需要挑8桶水
李和尚还需要挑7桶水
李和尚还需要挑6桶水
李和尚还需要挑5桶水
李和尚还需要挑4桶水
李和尚还需要挑3桶水
李和尚还需要挑2桶水
李和尚还需要挑1桶水

水挑完了

完成,两个和尚(线程)完美配合!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值