关于线程同步及其生产者与消费者问题

Synchronized

在Java中每一个对象都存在一个互斥锁(排他锁,对象锁),具体的使用是通过synchronizad关键字将对象锁定,此时,如果对象被一个线程锁定,则其他线程无法在操作当前对象,只有等待拥有该对象锁的线程释放锁之后,其他线程才能使用该对象。以上程序可以如下处理:

public void getMoney(double cash){
    //将对象锁定,当前线程释放对象锁之前,其他线程无法访问
    synchronized (account) {
        System.out.println("线程进入:"+Thread.currentThread().getName());
        //判断余额是否足够
        if(account.getMoney() >= cash){
            double d = account.getMoney() - cash;
            System.out.println("取款成功,取款:"+cash+",余额"+d);
            account.setMoney(d);
        }else{
            System.out.println("取款失败,余额不足");
        }
    }
}

以上操作即称之为线程同步。因此,synchronized语句块也称之同步块,synchronized不仅可以用于同步块,还能适用于同步方法,即在方法的声明上使用该关键字,如下

public synchronized void getMoney(double cash){
    System.out.println("线程进入:"+Thread.currentThread().getName());
    //判断余额是否足够
    if(account.getMoney() >= cash){
        double d = account.getMoney() - cash;
        System.out.println("取款成功,取款:"+cash+",余额"+d);
        account.setMoney(d);
    }else{
        System.out.println("取款失败,余额不足");
    }
}

生产者消费者(消息队列实现原理)

生产着消费者问题关键类包含以下几个:

  • 产品类(Product)
  • 仓库类(Storage)
  • 生产者(Producer)
  • 消费者(Consumer)

实现如下:

产品类(Mobile)
/**
 * 产品类(手机)
 * @author mrchai
 */
public class Mobile {

	/**id*/
	private int num;

	public Mobile(int num) {
		super();
		this.num = num;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

}
仓库类(Storage)
/**
 * 仓库类
 * @author mrchai
 */
public class Storage {

	/**存储产品的容器*/
	private Mobile[] list = new Mobile[10];
	/**用于表示生产或消费到的产品索引*/
	private int index;
	
	public synchronized void push(Mobile m){	
		while(index == list.length){
			try {
				System.out.println("仓库已满,等待消费..."); 
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//通知消费者消费
		notifyAll();
		list[index++] = m;
	}
	
	public synchronized Mobile pop(){		
		while(index == 0){
			try {
				System.out.println("仓库空,等待生产...");
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//通知生产者生产
		notifyAll();
		index--;
		Mobile m = list[index];
		return m;
	}
	
	public synchronized int size(){
		return index;
	}
}
生产者类(Producer)
/**
 * 消费者
 * @author mrchai
 *
 */
public class Consumer implements Runnable{

	private Storage s;
	private String name;
	
	public Consumer(Storage s,String name) {
		this.s = s;
		this.name = name;
	}
	
	@Override
	public void run() {
		
		while(true){
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			Mobile m = s.pop();
			System.out.println("消费者"+name+"消费一部手机--->"+m.getNum()+",剩余:"+s.size());
		}
		
	}

}

测试类(Test)
public class Test {

	public static void main(String[] args) {
		Storage s = new Storage();
		
		Producer p1 = new Producer(s,"A");
		Producer p2 = new Producer(s,"B");
		Producer p3 = new Producer(s,"C");
		new Thread(p1).start();
		new Thread(p2).start();
		new Thread(p3).start();
		
		Consumer c1 = new Consumer(s,"刘备");
		Consumer c2 = new Consumer(s,"关羽");
		Consumer c3 = new Consumer(s,"张飞");
		new Thread(c1).start();
		new Thread(c2).start();
		new Thread(c3).start();
	
	}
}

wait和sleep的区别?
sleep是Thread类中提供一个用于让当前线程休眠的方法,里面需要一个毫秒数作为参数,当sleep执行后,当前线程会进入休眠状态(让出cup的时间片),当休眠时间到达后,线程会自动唤醒继续执行,sleep不需要当前线程拥有任何对象的对象监视器(对象锁)。
wait是来之Object类中的一个方法,可以让一个线程进入等待状态,并且这种等待状态不能自动唤醒,需要其他线程通过调用该对象的notify或notifyAll来手动唤醒,wait必须要求当前线程拥有该对象的对想想监视器(对象锁),并且wait一旦执行,该线程就会释放在对象上的监视器。

你可能感兴趣的:(小白,刚入门)