Java多线程死锁,生产者与消费者模式,安全的单例模式

死锁

当两个线程的内部是 嵌套 锁定 执行两个相同对象,比如线程一里面先枷锁执行a对象,再在操作a对象的代码块里面加锁执行b对象,而线程二里面先加锁执行b对象,再在操作b对象的代码块中执行a对象,然后互相等待对方执行完成,以至于发生死锁,可看下图辅助理解

public class DeadLock {
	public static void main(String[] args) {
		Object o1=new Object();
		Object o2=new Object();
		Thread t1=new Thread(new A(o1,o2));
		Thread t2=new Thread(new B(o1,o2));
		t1.setName("俺是A");
		t2.setName("俺是B");
		t1.start();
		t2.start();
	}
}
class A implements Runnable{
	Object o1;
	Object o2;
	
	public A(Object o1,Object o2) {
		this.o1=o1;
		this.o2=o2;
	}
	
	@Override
	public void run() {
		synchronized(o2) {
			//加入睡眠是为了确定死锁一定会发生
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"锁住o2了");
			synchronized(o1) {
				System.out.println(Thread.currentThread().getName()+"锁住o1了");
			}
		}
	}
}

class B implements Runnable{
	Object o1;
	Object o2;
	
	public B(Object o1,Object o2) {
		this.o1=o1;
		this.o2=o2;
	}
	
	@Override
	public void run() {
		synchronized(o1) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"锁住o1了");
			synchronized(o2) {
				System.out.println(Thread.currentThread().getName()+"锁住o2了");
			}
		}
	}	
}

Object中的方法

wait(),将当前操作对象的线程挂起,会释放锁,让其他方法进行访问,

无参时或者参数为0时,表示不会自动唤醒,需要用notify方法进行唤醒;如果有一个long类型的参数,则表示到了指定时间后自动唤醒。

notify(),唤醒正在等待操作当前对象的其他某一线程

notifyAll(),唤醒正在等着操作对象的其他所有线程

守护线程

每个程序运行时,都会由一个守护线程进行监听程序是否正常运行

public class DaemonThread {
	public static void main(String[] args) {
		Thread thr = new Thread(new DaemonT());
//设置thr对象为守护线程,且设置守护线程要在start()方法之间设置
		thr.setDaemon(true);
		thr.start();
		// 当主线程执行完毕,jvm关机,守护线程终止
		for (int i = 0; i < 5; i++) {
			System.out.println(i);
		}
	}

}

class DaemonT implements Runnable {
	@Override
	public void run() {
		while (true) {
			System.out.println("sss");
		}
	}
}

生产者与消费者

生产者与消费者模式是,有一个中间容器,当生产者生产完产品之后,会将产品放到这个中间容器也叫缓冲区,而消费者则直接从缓冲区拿产品,降低了生产者与消费者之间的强耦合,所以此模式是为了降低耦合度

public class ProducerCustomer {
	public static void main(String[] args) {
		ProdCus pc = new ProdCus();
		Thread pro = new Thread(new Producer(pc));
		Thread cus = new Thread(new Customer(pc));
		pro.setName("生产者");
		cus.setName("消费者");
		pro.start();
		cus.start();
	}
}

class Producer implements Runnable {
	private ProdCus pc;

	public Producer(ProdCus pc) {
		this.pc = pc;
	}

	@Override
	public void run() {
		for (int i = 0; i < 15; i++) {
			pc.pro((char) ('a' + i));
		}
	}

}

class Customer implements Runnable {
	private ProdCus pc;

	public Customer(ProdCus pc) {
		this.pc = pc;
	}

	@Override
	public void run() {
		for (int i = 0; i < 15; i++) {
			pc.cus();
		}
	}

}

//业务类
class ProdCus {
	// 缓冲区
	char[] chars = new char[8];
	// 保存的个数,数量-1为数组下标
	int count = 0;

	// 放产品
	public synchronized void pro(char product) {
		// 当产品满了则等待消费者拿商品
		if (count == chars.length) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (count == 0)
			this.notifyAll();
		// 放产品
		chars[count++] = product;
		System.out.println("生产了" + chars[count-	1] + "共有" + count + "件产品");
	}

	// 拿产品
	public synchronized void cus() {
		// 当产品没了,就需要等待生产者生产商品
		if (count == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (count ==chars.length)
			this.notifyAll();
		// 拿走一个产品
		System.out.println("消费了" + chars[--count] + "还剩" + count + "件产品");
	}
}

单例模式

懒汉模式与饿汉模式在多线程模式下,只有懒汉模式会发生错误,因为饿汉模式在类加载时就创建了对象,多线程调用时就一直是这个对象;而懒汉模式则会在判断静态类类型的类变量是否为null时,进去多个线程,然后导致创建了多了对象,并进行赋值,以至于错误。

所以需要对创建并赋值对象的这段代码加锁,而给这块代码加锁后,在一个线程进去,其他线程就需要排队等待这个线程执行完毕,这样可能会效率较低,所以当对象创建并赋值时,应该让其他线程知道并不用等待,直接结束。

所以要用到双验证加锁机制进行设计

public class Singleton {
	public static void main(String[] args) {
		new Thread(new A1()).start();
		new Thread(new A1()).start();
		new Thread(new A1()).start();
		new Thread(new A1()).start();
		new Thread(new A1()).start();
		new Thread(new A1()).start();
	}

	private static Singleton obj;

	private Singleton() {
	}

//	public static Singleton getInstance() {
//		if (obj == null)// 另一个线程判断为null,也进来了
//			obj = new Singleton();// 多线程时,一个线程进行到这里还未赋值
//		return obj;
//	}
	public static Singleton getInstance() {
		if (obj == null) {
			synchronized (Singleton.class) {
				if (obj == null)
					obj = new Singleton();//当他进行赋值时,其他线程不用排队,直接返回结果
			}
		}
		return obj;
	}

}

class A1 implements Runnable {
	@Override
	public void run() {
		System.out.println(Singleton.getInstance());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值