Java----多线程详解(三)
5、线程同步和通信
当多个线程要访问同一个资源时,有必要使这个资源一次只能让一个线程访问,这就是下面要讲到的线程同步。线程通信是指线程之间通过一些方法进行访问。
1)、线程同步的必要性
经常有这个么一种情况,当网上书店库存量还有10本书时,俩了两个人分别买7本和8本,不管哪个人先买另一个都不可能完全满足要求,因为它的库存都是不够的,下面的程序以买书为例介绍多线程同步的必要性:
public class test{ public static void main(String[] str) { ShangDian sd = new ShangDian(10); PiFa pf = new PiFa(16, sd, "批发人"); GouMai gm1 = new GouMai(8, sd, "一号"); GouMai gm2 = new GouMai(7, sd, "二号"); GouMai gm3 = new GouMai(6, sd, "三号"); gm1.start(); gm2.start(); gm3.start(); pf.start(); }}class ShangDian{ int kucun = 0; public ShangDian(int kucun) { this.kucun = kucun; } public synchronized void PiFa(int i){ kucun += i; System.out.println(Thread.currentThread().getName() + "批发" + i + "本"); notifyAll(); } public synchronized void GouMai(int i){ while (i > kucun) { try { System.out.println(Thread.currentThread().getName() + "等待"); wait(); } catch (Exception e) { e.printStackTrace(); } } kucun -= i; System.out.println(Thread.currentThread().getName() + "购买" + i + "本"); }}class PiFa extends Thread{ int i; ShangDian sd; public PiFa(int i , ShangDian sd , Stringname) { this.i = i; this.sd = sd; this.setName(name); } @Override public void run() { sd.PiFa(i); }}class GouMai extends Thread{ int i; ShangDian sd; public GouMai(int i , ShangDian sd , Stringname) { this.i = i; this.sd = sd; this.setName(name); } @Override public void run() { sd.GouMai(i); }}其中一种运行结果为:
一号购买8本
二号等待
三号等待
批发人批发16本
三号购买6本
二号购买7本
本程序中,其实库存有10本,一号运行后买了8本。库存还有2本,这时二号三号分别购买7本和6本,库存不够,系统会调用wait()方法,使它们处于等待状态。然后调用管理员线程,批发16本,这时库存有18本,然后管理员线程调用notifyAll()方法通知处于等待状态中的二号三号。线程二号三号接到通知后进入运行状态,分别购买。