线程通信。文字不多,代码为主,自学用,谨慎借鉴,有错误请指正

以生产者和消费者为案例:生产者生产一件商品,消费者购买一件商品。

public class Product {
    private String brand;
    private String name;

    // setter,getter,toString
}
public class ProducerThread extends Thread {
    // 共享商品
    private Product p;

    public ProducerThread(Product product) {
        this.p = product;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            if (i % 2 == 0) {
                p.setBrand("费列罗");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                p.setName("巧克力");
            } else {
                p.setBrand("哈尔滨");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                p.setName("啤酒");
            }
            System.out.println("生产者生产了:" + p.getBrand() + "---" + p.getName());
        }

    }
}
public class Cuntomer extends Thread {
    private Product p;

    public Cuntomer(Product p) {
        this.p = p;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10 ; i++) {
            System.out.println("消费者消费了:" + p.getBrand() + "---" + p.getName());
        }
    }
}
    public static void main(String[] args) {
        Product p = new Product();
        ProducerThread pt = new ProducerThread(p);
        Cuntomer c = new Cuntomer(p);

        pt.start();
        c.start();
    }

造成原因:当生产者生产“哈尔滨啤酒”的时候,先打印“哈尔滨”,线程sleep(100)期间,消费者把线程资源抢走,并打印出哈尔滨。但因为“啤酒”是要睡完100ms后才能打印出来,所以在产品名称处才会打印出null。当消费者执行完后,线程资源才重新落回生产者这里, 所以才能循环打印出哈尔滨啤酒和费列罗巧克力

改进:仍存在生产者和消费者无法交叉进行交易的问题

同步代码块

public class ProducerThread extends Thread {
    // 共享商品
    private Product p;

    public ProducerThread(Product product) {
        this.p = product;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            synchronized (p){
                if (i % 2 == 0) {
                    p.setBrand("费列罗");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    p.setName("巧克力");
                } else {
                    p.setBrand("哈尔滨");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    p.setName("啤酒");
                }
                System.out.println("生产者生产了:" + p.getBrand() + "---" + p.getName());
            }

        }

    }
}
public class Cuntomer extends Thread {
    private Product p;

    public Cuntomer(Product p) {
        this.p = p;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10 ; i++) {
            synchronized (p){
                System.out.println("消费者消费了:" + p.getBrand() + "---" + p.getName());
            }
        }
    }
}

同步方法:

package com.yzc.threads.thread04;

public class Product {
    private String brand;
    private String name;

    // setter,getter,toString

    // 设置生产者生产商品的方法
    public synchronized void setProduct(String brand,String name){
        this.setBrand(brand);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.setName(name);
        System.out.println("生产者生产了:" + this.getBrand() + "---" + this.getName());
    }

    // 设置消费者获取商品的方法
    public synchronized void getProduct(){
        System.out.println("消费者消费了:" + this.getBrand() + "---" + this.getName());
    }
}
public class ProducerThread extends Thread {
    // 共享商品
    private Product p;

    public ProducerThread(Product product) {
        this.p = product;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            if (i % 2 == 0) {
                p.setProduct("哈尔滨", "啤酒");
            } else {
                p.setProduct("费列罗", "巧克力");
            }
        }
    }
}
public class Cuntomer extends Thread {
    private Product p;

    public Cuntomer(Product p) {
        this.p = p;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10 ; i++) {
            p.getProduct();
        }
    }
}

再次改进:解决生产者和交易者无法进行交叉交易的问题(使用wait()和notify())

public class Product {
    private String brand;
    private String name;
    boolean isExist = false;// ture:表示有商品;false:表示没有商品

    // setter,getter,toString


    public synchronized void setProduct(String brand, String name) {
        if(isExist == true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.setBrand(brand);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.setName(name);
        System.out.println("生产者生产了:" + this.getBrand() + "---" + this.getName());

        isExist = true;
        notify();
    }

    public synchronized void getProduct() {
        if(isExist == false){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费者消费了:" + this.getBrand() + "---" + this.getName());
        isExist = false;
        notify();
    }
}

ProducerThread和Cuntomer两个类代码不变,解决

其中wait()和notify():

 

 注意:

        这两个方法必须放在同步方法或者同步代码块中才生效,因为在同步的基础上进行线程通信才是有效的

        wait和sleep的区别,sleep进入阻塞装填后没有释放锁,wait进入阻塞状态的同时会释放锁

更进一步:

        如果生产者和消费者是多个的话,那么很有可能当生产者释放了锁后,另一个生产者抢到了资源,所以为了避免这个问题,可以将生产者和消费者放到两个不同的等待队列中

使用Lock和Condition类中的await(),signal(),signalAll

public class Product {
    private String brand;
    private String name;
    boolean isExist = false;// ture:表示有商品;false:表示没有商品

    Lock lock = new ReentrantLock();
    // 生产者等待队列
    Condition productCondition = lock.newCondition();
    // 消费者等待队列
    Condition constomerCondition = lock.newCondition();

    // setter,getter,toString   

    public void setProduct(String brand, String name) {
        lock.lock();
        try{
            if (isExist == true) {
                try {
                    productCondition.await();// 生产者阻塞,生产者进入等地队列中去
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            this.setBrand(brand);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.setName(name);
            System.out.println("生产者生产了:" + this.getBrand() + "---" + this.getName());

            isExist = true;
            // 通知消费者消费
            constomerCondition.signal();
        }finally {
            lock.unlock();
        }

    }

    public void getProduct() {
        lock.lock();
        try{
            if (isExist == false) {
                try {
                    constomerCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("消费者消费了:" + this.getBrand() + "---" + this.getName());
            isExist = false;
            // 通知生产者生产
            productCondition.signal();
        }finally {
            lock.unlock();
        }

    }
}

其余代码不变

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值