Java多线程——Day03

多线程Day 03

本文总结自B站狂神说JAVA

1. 线程同步

在Day01中有一个多个线程操作同一个对象的案例,没有处理好并发,所以出现了错误。解决方案:将需要同时访问该对象的线程进入这个对象的等待池形成队列,等前面的线程完毕,下一个线程才可以继续使用,这种方案叫做线程同步。线程同步必须要有队列和锁。说到底线程同步是用来解决线程的安全性问题。缺陷:会损失一部分性能,一个有锁的线程会导致其它需要此锁的线程挂起;一个优先级高的线程如果等待一个优先级低的线程的锁,会导致优先级倒置。
加锁的方法是:在需要同步的方法上添加synchroniezd关键字。该关键字默认锁的是添加它的方法。也可以生命一个synchroiezd代码块,将要同步的内容放到代码块中。

1.1 死锁

多个线程都在等待对方释放资源且一直处于停止的状态,某一个代码块同时拥有两个以上对象的锁,就会发生死锁的问题。

1.2 Lock 锁

每次只有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得lock对象。lock是显式锁,需要自动释放,只有代码块锁,jvm花费较少的时间来调用线程调度,性能更好。推荐使用lock。
定义锁:

private final ReentrantLock lock = new ReentrantLock();

加锁:
在要加锁的代码上面:

lock.lock();

解锁:

lock.unlock();

2. 线程协作

生产者消费者模式:生产者和消费者共享一个资源,并且相互依赖互为条件。生产者在完成生产任务时需要通知消费者去消费,消费者在消费完成之后,需要通知生产者再进行生产。

2.1 管程法

把生产者和消费者都放到缓冲区中。不直接的进行通信协作。

package com.rhdemo.PC;

/**
 * @date 2020/7/25 10:37
 * 缓冲区解决生产者消费者
 */
public class ProductAndCustomer01 {
    public static void main(String[] args) {
        SyncContainer syncContainer = new SyncContainer();
        new Product(syncContainer).start();
        new Customer(syncContainer).start();
    }
}

// 生产者
class Product extends Thread{
    SyncContainer container;

    public Product(SyncContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            container.push(new Goods(i));
            System.out.println("生产了"+i);
        }
    }
}

// 消费者
class Customer extends Thread{
    SyncContainer syncContainer;

    public Customer(SyncContainer syncContainer) {
        this.syncContainer = syncContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
             System.out.println("消费了"+syncContainer.pop().id);
        }
    }
}

// 产品
class Goods{
//    编号
    int id;

    public Goods(int id) {
        this.id = id;
    }
}

// 缓冲区
class SyncContainer{

//    容器大小
    Goods [] goods  = new Goods[10];

//    容器计数器
    int count = 0;

//    生产者放入产品
    public synchronized void push(Goods good){
//        容器满了就等待
        if (count  == goods.length){
//            通知消费者,等待消费之后再次生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        goods[count] = good;
        count++;

//        通知消费者
        this.notify();
    }

//   消费者进行消费
    public synchronized Goods pop(){
        if (count == 0){
//            等待生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

//        进行消费
        count--;
        Goods goodObj = goods[count];

//        通知生产者
        this.notify();

        return goodObj;
    }

}

2.2 信号灯法

package com.rhdemo.PC;

/**
 * @date 2020/7/25 10:55
 * 信号灯法
 */
public class PC2 {

    public static void main(String[] args) {
        Tv tv = new Tv();
        new Pro(tv).start();
        new Cus(tv).start();
    }

}

// 生产者->表演
class Pro extends Thread{
    Tv tv;

    public Pro(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 2; i++) {
            if (i%2 == 0){
                this.tv.play("快乐大本营");
            }else {
                this.tv.play("EDG VS RNG ");
            }
        }
    }
}

// 消费者->观众
class Cus extends Thread{
    Tv tv;

    public Cus(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 2; i++) {
            tv.watch();
        }
    }
}

// 产品
class Tv{
    String voice;
    boolean flag = true;

//    表演
    public synchronized void play(String voice){
        System.out.println("表演了"+voice);
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

//        通知观众
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }

//      观看
    public synchronized void watch(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看了"+voice);

//        通知演员表演
        this.notifyAll();
        this.flag = !this.flag;
    }
}

3.线程池

将创建好的线程放到线程池中,使用时获取,用完放回。提高响应速度,降低资源消耗。

/**
 * @date 2020/7/25 11:18
 * 线程池
 */
public class ThreadPool {
    public static void main(String[] args) {
//        创建线程池并且指定大小
        ExecutorService service = Executors.newFixedThreadPool(10);

//        开启线程
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

//        关闭
        service.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值