浅谈java线程

247 阅读2分钟

写在前面

  • 不经意间遇到个很低级的错误,这个错误来源于会用JS的push,呃~~。java里面的数组是没有增添元素的方法的。我居然找了好会儿的往数组里面添加元素的方法,惭愧惭愧。知晓的东西是会渐渐被淡忘的,所以趁热打铁,记录一下线程使用的一个小案例吧。小白初识线程,认知肯定不足,望各位看官多多指点。

案例需求

  • 就生产者消费者问题,实现需求: 生产1个商品便消费一个商品,即使多生产多消费亦是如此。
  • 想法:程序运行稳定后的状态应该是一次生产一次消费,但是由于抢锁是随机,那么就有了两种现象:
    • ① 用上Condition,每次唤醒的都是另一个线程,从运行过程上看,更像需求.
    • ② 不采用Condition,那么唤醒的随机,就依靠flag状态来决定执不执行线程逻辑.

采用Condition线程队列

  • 测试类格式如下,可以创建更多线程:
public class TheTest {
    public static void main(String[] args) {
        Goods goods = new Goods();
        new Thread(new Consumer(goods)).start();
        new Thread(new Producer(goods)).start();
        new Thread(new Consumer(goods)).start();
        new Thread(new Consumer(goods)).start();
    }
}
  • 商品类
public class Goods {
    private static int number = 0;
    // 用于切换执行各线程逻辑
    private static boolean flag = true;
    // 定义锁
    private static ReentrantLock lock = new ReentrantLock();
    // 定义生产线程队列
    private static Condition pro_ = lock.newCondition();
    // 定义消费线程队列
    private static Condition cus_ = lock.newCondition();

    // 生产
    public void product() {
        // 开始上锁
        lock.lock();
        // 唤醒消费者
        cus_.signal();
        if (flag){
            System.out.println("厂家生产了第" + (++number) + "个产品!");
            flag = !flag;
        }
        // 等待消费者信号再生产
        try {
            pro_.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 释放锁
        lock.unlock();
    }

    // 消费
    public void consume() {
        // 开始上锁
        lock.lock();
        // 就算消费者抢到了锁也要等待,每次都需要等生产者生产好才消费
        try {
            cus_.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!flag){
            System.out.println("买家消费了第" + (number--) + "个产品!");
            flag = !flag;
        }
        // 唤醒生产者
        pro_.signal();
        // 释放锁
        lock.unlock();
    }
}

  • 消费者类
public class Consumer implements Runnable {
    private Goods goods;

    public Consumer() {
    }

    public Consumer(Goods goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            goods.consume();
        }
    }
}
  • 生产者类
public class Producer implements Runnable {
    private Goods goods;

    public Producer() {
    }

    public Producer(Goods goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            goods.product();
        }
    }
}

不使用Condition

  • 其他不变,唯一变的就是Goods类:
public class Goods {
    private static int number = 0;
    // 一开始都没有商品,故生产线程必须先开始
    public static boolean flag = true;
    // 生产
    public synchronized void product() {
        // 确保第一次是生产者执行
        if (flag) {
            System.out.println("厂家生产了第" + (++number) + "个产品!");
            flag = !flag;
        }
        // 唤醒消费者
        notify();
        // 等待生产的信号
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 消费
    public synchronized void consume() {
        if (!flag) {
            System.out.println("买家消费了第" + (number--) + "个产品!");
            flag = !flag;
        }
        // 唤醒生产者
        notify();
        // 等待消费的信号
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}