线程安全应用:

线程安全应用:

ArrayList:

ArrayList是线程不安全的集合。

解决方案1:使用Vector – synchronized锁
 
解决方案2:使用Collections的synchronizedList方法将ArrayList转换为线程安全的集合 – synchronized锁

ArrayList<Object> list = new ArrayList<>();

List<Object> synchronizedList = Collections.synchronizedList(list);

 
解决方案3:使用CopyOnWriteArrayList – lock锁

CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<>();
	list.add("aaa");
	list.add("bbb");
	list.add("ccc");
	list.add("ddd");

​ 总结:Vector和synchronizedList()底层使用synchronized(重量级锁),效率很低。项目中推荐使用CopyOnWriteArrayList。

 
 

死锁:

死锁:多个线程中的多个锁对象被互相占用。
 
解决方案:尽可能的不要使用锁嵌套。

//哲学家1抢到a筷子,哲学家2抢到b筷子,发生死锁,程序不能进行。
public static void main(String[] args) {
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (KuaiZi.a) {
					//try {
					//	Thread.sleep(1);
					//} catch (InterruptedException e) {
					//	e.printStackTrace();
					//}
					synchronized (KuaiZi.b) {
						System.out.println("哲学家1吃饭饭");
					}
				}
			}
		}, "哲学家1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (KuaiZi.b) {
                    //休眠增加死锁概率
					//try {
					//	Thread.sleep(1);
					//} catch (InterruptedException e) {
					//	e.printStackTrace();
					//}
					synchronized (KuaiZi.a) {
						System.out.println("哲学家2吃饭饭");
					}
				}
			}
		}, "哲学家2");
		
		t1.start();
		t2.start();
		
	}

 

 

可重入锁:

​ 可重入锁:一个锁使用了一次之后,不需要立即解锁,就可再使用该锁一次。
 
​ 就是一个线程不用释放,可以重复的获取一个锁n次,只是在释放的时候,也需要相应的释放n次。
 
​ 简单来说:A线程在某上下文中获取了某锁,当A线程想要再次获取该锁时,不会因为锁已经被自己占用,而需要先等到锁的释放。

synchronized同步代码块是可重入锁。
synchronized同步方法是可重入锁。
Lock锁是可重入锁。

public class Task01 implements Runnable{

	@Override
	public void run() {
		synchronized (this) {
			System.out.println("获取到锁对象:" + this);
			
			synchronized (this) {
				System.out.println("获取到锁对象:" + this);
				
				System.out.println("释放锁对象:" + this);
			}
			
			System.out.println("释放锁对象:" + this);
		}
	}
}

public class Task02 implements Runnable{

	@Override
	public void run() {
		method1();
	}
	
	public synchronized void method1(){
		System.out.println("获取到锁对象:" + this);
		method2();
		System.out.println("释放锁对象:" + this);
	}
	
	public synchronized void method2(){
		System.out.println("获取到锁对象:" + this);
		
		System.out.println("释放锁对象:" + this);
	}
}

public class Task03 implements Runnable{

	private Lock lock = new ReentrantLock();
	
	@Override
	public void run() {
		
		lock.lock();
		System.out.println("获取到锁对象:" + this);
		lock.lock();
		System.out.println("获取到锁对象:" + this);
		lock.unlock();
		System.out.println("释放锁对象:" + this);
		lock.unlock();
		System.out.println("释放锁对象:" + this);
	}
}

 
 

生产者消费者模型:

​ 生产者消费者模型:重点加锁的逻辑放在线程中。

 

一个生产者一个消费者:

一个生产者一个消费者的情况。
 
步骤:
1.生产者线程、消费者线程不断的操作同一个产品对象
脏数据:
       null – 0.0
       华为 – 0.0
 
2.两个产品之间来回切换(目的:放大步骤1的问题)
脏数据:
       null – 0.0
       华为 – 0.0
       小米 – 3999.0
       华为 – 1999.0
出现原因:设置完品牌后,还没来得及设置价格,就被消费者线程抢到CPU资源。
解决方案:生产者线程设置完品牌+价格后,消费者线程才能执行自己的代码 – 加锁。
 
3.生产一个消费一个
产品类加一个库存的属性 – boolean store = false。
 
​ 生产者线程在每次生产之前都得判断是否有库存,有就等待(等待消费者线程消费后再生产),没有就生产。
 
​ 消费者线程在每次消费之前都得判断是否有库存,有就消费,没有就等待(等待生产者线程生产后再消费)。
 
​ 生产者线程和消费者线程互相唤醒。

public class Phone {
	
	private String brand;
	private double price;
	private boolean store;
	
	public Phone() {
	}

	public Phone(String brand, double price) {
		this.brand = brand;
		this.price = price;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}
	
	public boolean isStore() {
		return store;
	}

	public void setStore(boolean store) {
		this.store = store;
	}

	@Override
	public String toString() {
		return "Phone [brand=" + brand + ", price=" + price + "]";
	}
}

//生产者线程
public class Produce extends Thread{
	
	private Phone phone;
	
	public Produce(Phone phone) {
		this.phone = phone;
	}

	@Override
	public void run() {
		
		boolean flag = true;
		
		while(true){
            //phone是锁对象
			synchronized(phone){
				//phone是对象,调用phone的方法
				if(phone.isStore()){
					try {
						/**
						 * 等待:
						 * 		1.释放锁资源
						 * 		2.在对象监视器(phone)中记录当前线程被等待(阻塞)
						 * 		3.当前线程进入到阻塞状态
						 */
                        //phone为对象监视器
						phone.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				if(flag){
					phone.setBrand("华为");
					phone.setPrice(3999);
				}else{
					phone.setBrand("小米");
					phone.setPrice(1999);
				}
				flag = !flag;
				phone.setStore(true);
				
				phone.notify();//唤醒:唤醒对象监视器中任意一个线程
			}
		}
	}
}

//消费者线程
public class Consumer extends Thread{
	
	private Phone phone;
	
	public Consumer(Phone phone) {
		this.phone = phone;
	}

	@Override
	public void run() {
		while(true){
			synchronized(phone){
				
				if(!phone.isStore()){
					try {
						/**
						 * 等待:
						 * 		1.释放锁资源
						 * 		2.在对象监视器(phone)中记录当前线程被等待(阻塞)
						 * 		3.当前线程进入到阻塞状态
						 */
						phone.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				System.out.println(phone.getBrand() + " -- " + phone.getPrice());
				phone.setStore(false);
				
				phone.notify();//唤醒:唤醒对象监视器中任意一个线程
				
			}
		}
	}
}

public static void main(String[] args) {
		
		Phone phone = new Phone();
		
		Produce p = new Produce(phone);
		Consumer c = new Consumer(phone);
		
		p.start();
		c.start();
	}

 
 

多个生产者多个消费者:

//生产者线程
public class Produce extends Thread{
	
	private Phone phone;
	
	public Produce(Phone phone) {
		this.phone = phone;
	}
	
	private static boolean flag = true;
	@Override
	public void run() {
		
		while(true){
			synchronized(phone){
				
				while(phone.isStore()){
					try {
						/**
						 * 等待:
						 * 		1.释放锁资源
						 * 		2.在对象监视器(phone)中记录当前线程被等待(阻塞)
						 * 		3.当前线程进入到阻塞状态
						 */
						phone.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				if(flag){
					phone.setBrand("华为");
					phone.setPrice(3999);
				}else{
					phone.setBrand("小米");
					phone.setPrice(1999);
				}
				flag = !flag;
				phone.setStore(true);
				
				phone.notifyAll();//唤醒:唤醒对象监视器中所有线程
			}
		}
	}
}

//消费者线程
public class Consumer extends Thread{
	
	private Phone phone;
	
	public Consumer(Phone phone) {
		this.phone = phone;
	}

	@Override
	public void run() {
		while(true){
			synchronized(phone){
				
				while(!phone.isStore()){
					try {
						/**
						 * 等待:
						 * 		1.释放锁资源
						 * 		2.在对象监视器(phone)中记录当前线程被等待(阻塞)
						 * 		3.当前线程进入到阻塞状态
						 */
						phone.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				System.out.println(phone.getBrand() + " -- " + phone.getPrice());
				phone.setStore(false);
				
				phone.notifyAll();//唤醒:唤醒对象监视器中所有线程
				
			}
		}
	}
}

public static void main(String[] args) {
		
		Phone phone = new Phone();
		
		Produce p1 = new Produce(phone);
		Produce p2 = new Produce(phone);
		Consumer c1 = new Consumer(phone);
		Consumer c2 = new Consumer(phone);
		
		p1.start();
		p2.start();
		c1.start();
		c2.start();
	}

 
 

仓储模型:

仓储模型:重点加锁的逻辑放在线程外。

需求:
生产者线程不断的生产蛋糕(将蛋糕对象添加到仓库)。
消费者线程不断的消费蛋糕(将蛋糕对象从仓库中取出)。
先生产的蛋糕,先卖出。
 
分析:
1.蛋糕类、仓库类、生产者线程、消费者线程。
2.仓库类里有一个存放蛋糕对象的集合 – LinkedList。

 

一个生产者线程一个消费者线程:

对象监视器用谁:锁对象用谁,对象监视器就用谁。

//蛋糕类
public class Cake {

	private String brand;
	private String datetime;
	
	public Cake() {
	}

	public Cake(String brand, String datetime) {
		this.brand = brand;
		this.datetime = datetime;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getDatetime() {
		return datetime;
	}

	public void setDatetime(String datetime) {
		this.datetime = datetime;
	}

	@Override
	public String toString() {
		return "Cake [brand=" + brand + ", datetime=" + datetime + "]";
	}
}

import java.util.LinkedList;

//仓库类
public class Store {
	
	private int curCapacity;//当前容量
	private int maxCapacity;//最大容量
	private LinkedList<Cake> list;//蛋糕容器
	
	public Store(int maxCapacity) {
		this.maxCapacity = maxCapacity;
		list =  new LinkedList<>();
	}
	
	//入库(此方法被生产者线程不断的调用)
	public synchronized void push(Cake cake){
		if(curCapacity >= maxCapacity){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		list.add(cake);
		curCapacity++;
		System.out.println("入库 - 当前容量为:" + curCapacity);
		this.notify();
	}
	
	
	//出库(此方法被消费者线程不断的调用)
	public synchronized Cake pop(){
		if(curCapacity <= 0){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Cake cake = list.removeFirst();
		curCapacity--;
		System.out.println("出库 - 当前容量为:" + curCapacity + ",卖出的蛋糕为:" + cake);
		this.notify();
		return cake;
	}
	
}

import java.time.LocalDateTime;

//生产者线程
public class Produce extends Thread{

	private Store store;

	public Produce(Store store) {
		this.store = store;
	}
	
	@Override
	public void run() {
		while(true){
			Cake cake = new Cake("桃李", LocalDateTime.now().toString());
			store.push(cake);
		}
	}
}

//消费者线程
public class Consumer extends Thread{
	
	private Store store;
	
	public Consumer(Store store) {
		this.store = store;
	}

	@Override
	public void run() {
		while(true){
			store.pop();
		}
	}
}

public static void main(String[] args) {
		
		Store store = new Store(20);
		
		Produce p = new Produce(store);
		Consumer c = new Consumer(store);
		
		p.start();
		c.start();
	}

 

 

多个生产者线程多个消费者线程:

import java.util.LinkedList;

//仓库类
public class Store {
	
	private int curCapacity;//当前容量
	private int maxCapacity;//最大容量
	private LinkedList<Cake> list;//蛋糕容器
	
	public Store(int maxCapacity) {
		this.maxCapacity = maxCapacity;
		list =  new LinkedList<>();
	}
	
	//入库(此方法被生产者线程不断的调用)
	public synchronized void push(Cake cake){
		while(curCapacity >= maxCapacity){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		list.add(cake);
		curCapacity++;
		System.out.println("入库 - 当前容量为:" + curCapacity);
		this.notifyAll();
	}
	
	//出库(此方法被消费者线程不断的调用)
	public synchronized Cake pop(){
		while(curCapacity <= 0){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Cake cake = list.removeFirst();
		curCapacity--;
		System.out.println("出库 - 当前容量为:" + curCapacity + ",卖出的蛋糕为:" + cake);
		this.notifyAll();
		return cake;
	}
	
}

public static void main(String[] args) {
		
		Store store = new Store(20);
		
		Produce p1 = new Produce(store);
		Produce p2 = new Produce(store);
		Consumer c1 = new Consumer(store);
		Consumer c2 = new Consumer(store);
		
		p1.start();
		p2.start();
		c1.start();
		c2.start();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值