黑马程序员---Java多线程(2)

------- android培训java培训、期待与您交流! ----------

1.当单例模式遇到多线程

单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。
但是如果在多线程并发执行情况下,可能会出现多个实例的现象,解决办法如下:   
//懒汉式
public class Single2 {
	private static Single2 s = null;
	private Single2() {
	}
	public static Single2 getInstance() {
		if (s == null) {
			synchronized (Single2.class) {
				if (s == null) {
					s = new Single2();
				}
			}
		}
		return s;
	}
}
当然对于饿汉式,不存在这个问题;
//饿汉式
public class Single {
	private static final Single s = new Single();
	private Single(){}
	public static Single getInstance(){
		return s;
	}
}

2.多线程间通信(生产者和消费者问题)

如果程序中只有2个线程,一个负责生产,一个负责消费,那么如下就可以解决:
public class Resource {
	private String name;
	private String sex;
	private boolean flag;

	public synchronized void set(String name, String sex) {
		if (flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}

	public synchronized void out() {
		if (!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(this.name + "  " + this.sex);
		flag = false;
		this.notify();
	}

	public boolean getFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}
}

但是如果有多个生产线程和消费线程的时候,上面的做法就不能正确执行了,还可能会出现死锁的现象。可以采取一下的方式:
public synchronized void set(String name, String sex) {
		while (flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notifyAll();
	}
	public synchronized void out() {
		while (!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(this.name + "  " + this.sex);
		flag = false;
		this.notifyAll();
	}
采用while防止线程被唤醒后不去判断Flag而直接向下执行, 为了保证一定能唤醒需要的线程,采取notifyAll()方式,将线程池中所有被wait的线程都唤醒

但是这样会带来新的难题,如果每次都把所有被wait的线程唤醒,很影响执行效率。

为此在JDK1.5以后,有了新的处理方式:

接口 Lock

Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的
Condition对象。

ConditionObject 监视器方法(waitnotifynotifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待 

set(wait-set)。其中,Lock 替代了synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。  

使用也十分方便,可以改成如下:

public class Res {
	private String name;
	private int count = 1;
	private boolean flag = false;
	private Lock lock = new ReentrantLock();
	private Condition pro_con = lock.newCondition();
	private Condition cum_con = lock.newCondition();
	public void set(String name) {
		lock.lock();
		try {
			while (flag) {
				try {
					pro_con.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			this.name = name + count;
			count++;
			System.out.println(Thread.currentThread().getName() + "produce"
					+ this.name);
			flag = true;
			cum_con.signal();
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			lock.unlock();
		}

	}

	public  void out() {
		lock.lock();
		try {
			while (!flag) {
				try {
					cum_con.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName() + "consume"
					+ this.name);
			flag = false;
			pro_con.signal();
			
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			lock.unlock();
		}
	}
}

在查看JDK时候看到下面代码,对数组的多线程处理,很有思路

class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }
 











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值