多线程_线程同步

多线程之间除有互斥情况外, 还需要 同步, 通俗地理解,就是要按顺序执行。

当线程A 使用到某个对象, 而此对象 又需要线程B修改后才能符合本线程的需要。 这时线程 A 就要等待线程B 完 成修改工作。 这种线程相互等待称为线程的同步。


一 为实现同步, Java 提供wait(),  notify(),  notifyAll() 三个方法供线程 在临界段中使用。  

 1. 使用 wait() 时,使执行该方法的线程等待, 并允许 其他线程使用这个临界段。  这个方法是多态的,有以下两种形式:

wait(),  让线程一直等待, 直到被 notify() 或notifyAll()  方法唤醒

wait(long timeout) , 让线程等待到被唤醒, 或经过指定时间后结束等待.


2.  当线程使用完临界段后, 用notify() 方法通知由于想使用这个临界段而处于 等待的线程 结束等待.


     notify() 方法只是通知第一个处于等待的线程, 

     如果某个线程在使用完临界段方法后,其他早先等待的线程都可结束等待, 重新竞争CPU, 则可以使用 notifyAll()  方法。


一个例子, 应用程序模拟一群顾客购买纪念品, 纪念品5元一个, 有人持5元, 有人持10元购买纪念品,持5元的能立即购买,持10元的,如果销售员有可找的零钱,也以立即购买, 如果没有可找的零钱,则这位顾客就得等待。 以下程序模拟顾客购买的过程

public class Example8_5 {

	//这里14表示 14个纪念品
	static SalesLady salesLady = new SalesLady(14, 0, 0);
	
	public static void main(String[] args) {
		//所有纪念品
		int moneies[] = { 10, 10, 5, 10, 5,   10, 5, 5, 10, 5};
		Thread[] threadArray = new Thread[10];
		System.out.println("现在开始购买");
		for (int i = 0; i < moneies.length; i++) {
			threadArray[i] = new Thread(new CustomerClass(i + 1, moneies[i]));
			threadArray[i].start();
		}
		// 等待所有线程结束
		while (true) {
			for (int i = 0; i < moneies.length; i++) {
				if (threadArray[i].isAlive()) {
					continue;
				}
			}
			break;
		}
		System.out.println("购买结束");
		
	}

}


public  class CustomerClass implements Runnable {

	int num, money; // 顾客序号, 钱的面值

	@Override
	public void run() {
		System.out.println("我是" + num + "号顾客, 用 " + money
				+ "元购买纪念品, 售货员说:" + Example8_5.salesLady.ruleForSale(num, money));
	}

	public  CustomerClass(int n, int m) {
		num = n;
		money = m;
	}

}

public class SalesLady {

	int memontoes, five, ten; // 销售员纪念品数, 5、10 元张数

	public synchronized String ruleForSale(int num, int money) {

		// 购买过程为临界段
		String s = null;
		if (memontoes == 0) {
			return "对不起,已售完";
		}
		switch (money) {
		case 5:
			memontoes--;
			five++;
			s = "给你一个纪念品,你的钱正好";
			break;
		case 10:
			while (five < 1) {
				System.out.println(num + "号顾客用10元钱购票, 发生等待!");
				try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
				memontoes--;
				five -= 1;
				ten++;
				s = "给你一个纪念品,你给了10元,找你5元";
			break;
		}
		notify();// 通知后面等待的顾客
		return s;

	}

	public SalesLady(int m, int f, int t) {
		memontoes = m;
		five = f;
		ten = t;
	}

}

运行结果: 


结果显示文字的顺序有些 出入,整 个流程是正确的。

请注意实现线程同步的一般原则: 如果两上或多个线程 修改同一个对象,  那么将执行 修改的操作方法用 synchronized 修饰, 使它成为临界段。

如果进入临界段的线程必须等待某个对象的状态被改变, 那么应调用 wait() 方法,反之当别一个进入临界段的线程修改了某个对象的状态后,就应该调用 notify() 方法,及时通知那些处于等待的线程。


有3种类型 的代码段能够作为临界段: 类方法, 实例方法,一个方法中的代码块。 下面的同步方法:

   synchronized void myMethod() {


   }

等价于

    void myMethod() {

synchronized (this)   {    

     }

  }

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值