多线程下的单例模式、生产者、消费者模式

单例模式

  • 之前有一个博客简述了单例模式,这里就不具体介绍了
  • 单例模式的实现方式:懒汉式和饿汉式
  • 其中,懒汉式是线程不安全的,当有多条线程同时访问单例对象时,则会出现多线程临界资源问题
多线程下的懒汉式
package waking.test.xcms;
/**
 * 多线程下的单例模式
 * 懒汉式
 * @author waking
 *
 */

import java.util.HashSet;

public class Demo01 {
	//创建set集合
	static HashSet<Kind> hs = new HashSet<Kind>();
	//静态Runnable
	static Runnable r = new Runnable() {
		
		@Override
		public void run() {
			Kind kind = Kind.getKindInstance();
			hs.add(kind);
		}
	};
	
	public static void main(String[] args) {
		for (int i = 0; i < 1000; i++) {
			Thread t = new Thread(r);
			t.start();
		}
		
		System.out.println(hs);
		//[waking.test.xcms.Kind@5acbf04a, waking.test.xcms.Kind@5162c257, waking.test.xcms.Kind@5e05618a]

	}

}
class Kind {
	//私有化对象
	private static Kind kind = null;
	
	//私有化构造方法
	private Kind() {
		
	}
	
	//向外提供公开的静态的实例对象
	public static Kind getKindInstance() {
		if(kind==null) {
			kind = new Kind();
		}
		
		return kind;
	}
}
  • 由此可见线程不安全
多线程下的饿汉式
package waking.test.xcms;
/**
 * 多线程下的单例模式
 * 饿汉式
 * @author waking
 *
 */

import java.util.HashSet;

public class Demo02 {
	//set集合
	static HashSet<Hungry> hs = new HashSet<Hungry>();
	
	//Runnable
	static Runnable r = new Runnable() {

		@Override
		public void run() {
			Hungry h = Hungry.getHungryInstance();
			hs.add(h);
		}
		
	};
	
	public static void main(String[] args) {
		for (int i = 0; i < 1000; i++) {
			Thread t = new Thread(r);
			t.start();
		}
		
		System.out.println(hs);
		//[waking.test.xcms.Hungry@30535167]
	}
}

/**
 * 饿汉式
 * @author waking
 *
 */
class Hungry{
	//私有化静态对象
	private static Hungry hungry = new Hungry();
	
	//私有化静态方法
	private Hungry() {
		
	}
	
	//提供公开的静态的实例方法
	public static Hungry getHungryInstance() {
		return hungry;
	}
	
}
  • 由此可以看出,饿汉式相对线程安全

生产者、消费者模式

原理
  • 它描述的是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者可以从仓库中取走产品,解决生产者、消费者问题,我,们需要采用某种机制保护生产者和消费者的同步
  • 同步的问题核心在于:如何保证同一个资源被多个线程并发访问时的完整性,常用的方法就是加锁,保证资源在任意时刻只被一份线程访问
实现
  • 方式一:采用wait()、notify()和notifyAll()方法
wait():当缓冲区已满或空时,生产者、消费者线程停止自己的执行,放弃锁,使用自己处于等待状态,让其他线程执行
说明:
a.是Object的方法
b.调用方式:对象.wait();
c.表示释放、对象这个锁标记,然后在锁外面等待(对比sleep(),sleep()是抱着锁休眠的)
d.等待,必须放到同步代码中执行
notify():当生产者、消费者向缓冲区放入、取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态
说明:
a.是object的方法
b.调用方式:对象.notify();
c.表示唤醒对象所标记外边在等待的一个线程
notifyAll():全部唤醒
a.是objectde 方法
b.调用方式:对象.notifyAll()
c.表示唤醒对象所标记外边等待的所有线程
package waking.test.xcms;
/**
 * 生产者消费者模式
 * @author waking
 *
 */
public class Demo03 {
	//标志
	static boolean shouldProduct = true;
	
	//生产者线程
	static class Productor implements Runnable{
		
		private Product product;

		public Productor(Product product) {
			this.product = product;
		}

		@Override
		public void run() {
			while(true) {
				synchronized ("") {
					if(shouldProduct) {
						this.product.setName("waking");
						System.out.println("生产者:"+Thread.currentThread().getName()+"生产了,一个"+this.product);
						shouldProduct=false;
						
						"".notifyAll();
					}else {
						try {
							"".wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
		}
		
	}
	//消费者线程
	
	static class Consumer implements Runnable{

		private Product P;
		
		

		public Consumer(Product p) {
			this.P = p;
		}



		@Override
		public void run() {
			while(true) {
				synchronized ("") {
					if(shouldProduct) {
						try {
							"".wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}else {
						System.out.println("消费者:"+Thread.currentThread().getName()+"消费了,一个产品"+this.P);
						shouldProduct=true;
						"".notifyAll();
					}
				}
			}
		}
		
	}
	
	public static void main(String[] args) {
		Product p = new Product();
		Productor por = new Productor(p);
		Thread t = new Thread(por,"A");
		Thread t2 = new Thread(por,"B");
		Thread t3 = new Thread(por,"C");
		Thread t4 = new Thread(por,"D");
		t.start();
		t2.start();
		t3.start();
		t4.start();
		
		Consumer c = new Consumer(p);
		Thread t5 = new Thread(c,"a");
		Thread t6 = new Thread(c,"b");
		Thread t7 = new Thread(c,"c");
		Thread t8 = new Thread(c,"d");
		t5.start();
		t6.start();
		t7.start();
		t8.start();
	}

}
class Product{
	private String name;
	int id;
	public String getName() {
		id--;
		return name;
	}
	public void setName(String name) {
		this.name = name;
		id++;
	}
	@Override
	public String toString() {
		return "Product [name=" + name + ", id=" + id + "]";
	}
	
	
}
  • 采用ReentrantLock类中的newCondition()方法结合Condition类中的await()、signal()和signalAll()方法
package waking.test.xcms;
/**
 * 生产者消费者模式二
 * @author waking
 *
 */

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Demo04 {
	//标志
	static boolean flage = true;
	
	static ReentrantLock lock = new ReentrantLock();
	//生产者标志
	static Condition c1 = lock.newCondition();
	//消费者标志
	static Condition c2 = lock.newCondition();
	
	//生产者线程
	static class Pro implements Runnable{

		private S s;
		
		
		public Pro(S s) {
			super();
			this.s = s;
		}


		@Override
		public void run() {
			while(true) {
				try {
					//加锁
					lock.lock();
					if (flage) {
						this.s.setName("waking");
						System.out.println("生产者:" + Thread.currentThread().getName() + "生产了" + this.s);
						flage = false;
						//唤醒
						c2.signalAll();
					} else {
						try {
							c1.await();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					} 
				} finally {
					lock.unlock();
				}
			}
		}
		
	} 
	//消费者线程
	static class Con implements Runnable{

		private S ss;
		
		
		public Con(S ss) {
			super();
			this.ss = ss;
		}


		@Override
		public void run() {
			while(true) {
				try {
					lock.lock();
					if (flage) {
						try {
							c2.await();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					} else {
						System.out.println("消费者:" + Thread.currentThread().getName() + "消费了" + this.ss);
						flage = true;
						c1.signalAll();
					} 
				} finally {
					lock.unlock();
				}
			}
		}
		public static void main(String[] args) {
			S s = new S();
			Pro p = new Pro(s);
			new Thread(p,"A").start();
			new Thread(p,"B").start();
			new Thread(p,"C").start();
			new Thread(p,"D").start();
			
			Con c = new Con(s);
			new Thread(c, "a").start();
			new Thread(c, "b").start();
			new Thread(c, "c").start();
			new Thread(c, "d").start();
			
		}
		
	}
	

}
class S{
	private String name;
	int id;
	
	public String getName() {
		id--;
		return name;
	}
	public void setName(String name) {
		this.name = name;
		id++;
	}
	@Override
	public String toString() {
		return "S [name=" + name + ", id=" + id + "]";
	}
	
}
以上是多线程下的单例模式、生产者、消费者模式的情况,感谢您的观看
发布了16 篇原创文章 · 获赞 15 · 访问量 2381

猜你喜欢

转载自blog.csdn.net/weixin_43688349/article/details/104178734