线程安全应用:
线程安全应用:
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();
}