zoukankan      html  css  js  c++  java
  • Java多线程

    前言

    在拥有多核CPU的情况下,Java的线程可以被同时调度到不同的CPU上,同时执行;这是Python线程和Java线程的区别;

    Java默认会有3个线程分别为main方法对应的线程(主线程)、处理异常的线程(异常处理线程)和垃圾收集器线程(GC线程);

    其中异常处理线程可以中断主线程的执行;

    无论使用什么语言,在并行和并发编程模式下都会遇到同类线争抢同1个资源这样的内部矛盾,也会遇到不同类线程如何完成同步通信这样的外部矛盾;

    在Golang中使用锁解决Gorutine争抢资源的问题,使用channel解决Gorutine之间数据通信,注意这是在通过2种方法解决2种不同的问题;

    如果多个线程之间要想通信就需要有1个共同的通信介质,这就又回到多个线程争抢同1个资源的问题上,所以锁是实现线程间通信的基础。 

    一、线程创建

    在Java中我们可以通过3种方式创建线程。

    1.继承Thread类 

    我们可以通过继承java.lang.Thread类的方式开生成线程对象;

    package Threads;
    
    //1):定义一个类A继承于java.lang.Thread类.
    class MusicThread extends Thread {
        //2):在A类中覆盖Thread类中的run方法.
        public void run() {
            //3):在run方法中编写需要执行的操作
            for (int i = 0; i < 50; i++) {
                System.out.println("播放音乐" + i);
            }
        }
    }
    
    class CreateThread01 {
        public static void main(String[] args) {
            for (int j = 0; j < 50; j++) {
                System.out.println("运行游戏" + j);
                if (j == 10) {
                    //4):在main方法(线程)中,创建线程对象,并启动线程.
                    MusicThread music = new MusicThread();
                    music.start();
                }
            }
        }
    }

    1.2.设置和读取线程名称

    (1)setName和getName

    我们可以调用setName和getName方法,给线程设置名称以帮助我们区分线程。

    package Threads;
    
    //定义一个类A继承于java.lang.Thread类.
    class MusicThread extends Thread {
        public void run() {
            for (int i = 0; i < 50; i++) {
                //4.获取子线程名称
                String Threadname = super.getName();
                System.out.println(Threadname + "播放音乐" + i);
            }
        }
    }
    
    class CreateThread01 {
        public static void main(String[] args) {
            for (int j = 0; j < 50; j++) {
                //1.主线程设置线程名称
                Thread.currentThread().setName("Game线程");
                //2.主线程获取线程名称
                System.out.println(Thread.currentThread().getName() + "运行游戏" + j);
                if (j == 10) {
                    MusicThread music = new MusicThread();
                    //3.设置子线程的名称
                    music.setName("Muisc线程");
                    music.start();
                }
            }
        }
    }

    (2)构造器设置线程名称

    还可以在构造线程对象时,就给线程设置名称。

    package Threads;
    
    //定义一个类A继承于java.lang.Thread类.
    class MusicThread extends Thread {
        public MusicThread(String name) {
            super(name); //2.调用父类的有参构造器
        }
    
        public void run() {
            for (int i = 0; i < 50; i++) {
                //3.获取子线程名称
                System.out.println(this.getName() + "播放音乐" + i);
            }
        }
    }
    
    class CreateThread01 {
        public static void main(String[] args) {
            for (int j = 0; j < 50; j++) {
                System.out.println("运行游戏" + j);
                if (j == 2) {
                    //1.利用构造器设置子线程名称
                    MusicThread music = new MusicThread("音乐线程" + j);
                    music.start();
                }
            }
        }
    }

     1.3.抢火车票

    package Threads;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //购票窗口
    class TicketWindow extends Thread {
        //一共10张车票:多个线程对象共享10张票;
        static int ticketNum = 10;
        //加锁
        Lock lock = new ReentrantLock();
    
        public TicketWindow(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            //100个人抢10张票
            for (int i = 0; i <= 100; i++) {
                //判断是否售罄?
                if (ticketNum > 0) {
                    lock.lock();
                    ticketNum--;
                    System.out.printf("我在%s买到了从北京到哈尔滨的第%s张车票。\n", super.getName(), ticketNum);
                    lock.unlock();
                }
    
            }
        }
    }
    
    
    public class BuyTicket02 extends Thread {
        public static void main(String[] args) {
            TicketWindow t1 = new TicketWindow("窗口1");
            t1.start();
            TicketWindow t2 = new TicketWindow("窗口2");
            t2.start();
            TicketWindow t3 = new TicketWindow("窗口3");
            t3.start();
        }
    
    }

    2.实现Runnable接口

     我们可以通过实现Runabke接口,制造线程对象。

    package Threads;
    
    //实现Runnable接口
    class TestThread implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }
    
    
    public class CreateThread02 {
        public static void main(String[] args) {
            //创建子线程对象
            TestThread tt = new TestThread();
            Thread t = new Thread(tt, "子线程");
            t.start();
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + i);
            }
    
    
        }
    
    }

    2.1.抢火车票

    package Threads;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //实现Runnable接口
    class TestThread implements Runnable {
        int ticketNumber = 10;
        private Lock lock = new ReentrantLock();
    
        @Override
        public void run() {
            for (int i = 1; i < 100; i++) {
                lock.lock();
                if (ticketNumber > 0) {
                    ticketNumber--;
                    System.out.printf("我在%s抢到了北京到保定的第%d张票\n", Thread.currentThread().getName(), ticketNumber);
    
                }
                lock.unlock();
    
    
            }
        }
    }
    
    
    public class CreateThread02 {
        public static void main(String[] args) {
            //创建1个线程对象共享票和锁
            TestThread tt = new TestThread();
            //开启线程1
            Thread t1 = new Thread(tt, "窗口1");
            t1.start();
            //开启线程2
            Thread t2 = new Thread(tt, "窗口2");
            t2.start();
            //开启线程3
            Thread t3 = new Thread(tt, "窗口3");
            t3.start();
    
    
        }
    
    }

    3.实现Calable接口

    以上两种创建线程的方式,都需要有1个run(),run方法的不足之处就是无法有返回值也无法抛出异常

    package Threads;
    
    import java.util.Random;
    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    class TestThread03 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            return new Random().nextInt(100);
        }
    }
    
    public class CreateThread03 {
        public static void main(String[] args) throws Exception {
            //定义1个线程对象
            TestThread03 tr = new TestThread03();
            FutureTask ft = new FutureTask(tr);
            Thread t3 = new Thread(ft);
            t3.start();
    
            //获取线程得到的返回值
            Object obj = ft.get();
            System.out.println(obj);
    
    
        }
    }

    4.线程的生命周期

     

    二、线程的常用方法

    线程创建完成之后,我们可以调用线程对象中封装的一些API对线程进行操作;

    1.setPriority()

    我们可以通过setPriority设置线程被CPU调度的优先级。

        * The minimum priority that a thread can have.
         */
        public final static int MIN_PRIORITY = 1;
    
       /**
         * The default priority that is assigned to a thread.
         */
        public final static int NORM_PRIORITY = 5;
    
        /**
         * The maximum priority that a thread can have.
         */
        public final static int MAX_PRIORITY = 10;

    正常优先级 为5,最小优先级为1,最大优先级为10;

    package Threads;
    
    class Task01 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("task01--" + i);
            }
        }
    }
    
    class Task02 extends Thread {
        @Override
        public void run() {
            for (int i = 20; i < 30; i++) {
                System.out.println("task02--" + i);
            }
        }
    }
    
    public class ThreadMthods {
        public static void main(String[] args) {
            Task01 t1 = new Task01();
            //设置线程1的优先级别为1
            t1.setPriority(1);
            t1.start();
    
            //设置线程2的优先级别为10
            Task02 t2 = new Task02();
            t1.setPriority(10);
            t2.start();
        }
    }

    2.join()

    当一个线程调用了join方法之后,这个线程就会优先被执行;

    当它执行结束后,CPU才可以去执行其他线程;

    注意:线程必须先执行start()再执行join(),才能生效;

    package Threads;
    
    
    class Task03 extends Thread {
        Task03() {
        }
    
        Task03(String name) {
            super.setName(name);
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(this.getName() + i);
            }
        }
    }
    
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            for (int i = 0; i < 100; i++) {
                if (i == 6) {
                    Task03 t3 = new Task03("子线程");
                    t3.start();
                    t3.join(); //半路杀出个程咬金
    
                }
                Thread.currentThread().setName("main线程");
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }

    3.sleep()

    我们可以通过sleep()方法阻塞当前线程;

    package Threads;
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            System.out.println("开始");
            Thread.sleep(6000); //线程阻塞6秒,再进入就绪状态,在被CPU调度
            System.out.println("结束");
        }
    }

    4.setDaemon(true)

    在古代皇帝死了,他的妃子通常会哭的很惨,因为接下来她也要殉葬;

    在Python中子线程默认就是主线程的守护线程,一旦主线程提前结束,子线程即使没有结束也要强制其结束; 

    而Java中的线程是跑在不同的CPU上的,主线程和子线程的地位是平等的;

    在Java中,默认情况下即使主线程结束了,子线程也可以继续执行;

    但是只要我们把子线程设置为守护线程,一旦主线程结束,子线程会立即结束;

    package Threads;
    
    class Task extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println("子线程" + i);
            }
        }
    }
    
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            Task t1 = new Task();
            t1.setDaemon(true);//注意先设置守护线程,在启动该线程
            t1.start();
            //在Python中子线程默认就是主线程的守护线程,一旦主线程提前与子线程结束,子线程即使没有结束也要强制其结束;
            //而Java的线程可以跑在不同的CPU上,主线程和子线程是平等的;默认情况下即使主线程结束了,子线程也可以继续执行;
            for (int i = 0; i < 10; i++) {
                System.out.println("主线程" + i);
            }
        }
    }

    5.stop()

    我们可以通过调用stop方法,来结束当前线程;

    package Threads;
    
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            for (int i = 1; i < 11; i++) {
                if (i == 7) {
                    Thread.currentThread().stop();
                }
                System.out.println("主线程" + i);
            }
        }
    }

    三、线程安全问题(内部矛盾)

    我这里所说的线程安全问题即 N个执行相同任务的线程,争抢同1个资源;

    例如:100个人在北京西站去抢10张北京到哈尔滨的火车票;

    在Java中我们可以通过同步代码块、静态同步方法、显示锁解决这种问题;

    1.synchronized ()同步代码块

    package Threads;
    
    
    class TicketAgency extends Thread {
        static int tickets = 10;
    
        TicketAgency() {
        }
    
        TicketAgency(String name) {
            super.setName(name);
        }
    
        @Override
        public void run() {
            //确保每个线程对象,使用的都是同一把锁。不要使用this
            synchronized ("zhanggen") {
                for (int i = 0; i <= 100; i++) {
                    if (tickets > 0) {
                        System.out.printf("我在%s,抢到了北京到哈尔滨的第%d张票!\r\n", super.getName(), tickets--);
                    }
                }
            }
        }
    }
    
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            TicketAgency agency01 = new TicketAgency("窗口1");
            agency01.start();
            TicketAgency agency02 = new TicketAgency("窗口2");
            agency02.start();
            TicketAgency agency03 = new TicketAgency("窗口3");
            agency03.start();
    
        }
    }

    2.静态同步方法

    public static synchronized
    package Threads;
    
    
    class TicketAgency extends Thread {
        static int tickets = 10;
    
        TicketAgency() {
        }
    
        TicketAgency(String name) {
            super.setName(name);
        }
    
        @Override
        public void run() {
            //必须确保多个线程对象,使用的都是同1把锁。不要使用this
            for (int i = 0; i <= 100; i++) {
                buyTicket();
            }
    
        }
    
        //同步方法:增加static修饰符,确保锁住的不是this
        public static synchronized void buyTicket() {
            if (tickets > 0) {
                System.out.printf("我在%s,抢到了北京到哈尔滨的第%d张票!\r\n", Thread.currentThread().getName(), tickets--);
            }
        }
    }
    
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            TicketAgency agency01 = new TicketAgency("窗口1");
            agency01.start();
            TicketAgency agency02 = new TicketAgency("窗口2");
            agency02.start();
            TicketAgency agency03 = new TicketAgency("窗口3");
            agency03.start();
    
        }
    }

    3.Lock类

    synchronized是Java中的关键字,这个关键字的识别是依靠JVM来识别完成的,是虚拟机级别的;

    在JKD1.5之后我们可以通过API级别的Lock显示锁(自己lock+unlock)实现同步,这种方式更加灵活。

    package Threads;
    
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class TicketAgency extends Thread {
        static int tickets = 10;
        //拿来一把锁
        Lock lock = new ReentrantLock(); //多态 接口=实现类
    
        TicketAgency() {
        }
    
        TicketAgency(String name) {
            super.setName(name);
        }
    
        @Override
        public void run() {
            for (int i = 0; i <= 100; i++) {
                lock.lock();
                if (tickets > 0) {
                    System.out.printf("我在%s,抢到了北京到哈尔滨的第%d张票!\r\n", Thread.currentThread().getName(), tickets--);
                }
                lock.unlock();
    
            }
    
        }
    
    }
    
    
    public class ThreadMthods {
        public static void main(String[] args) throws Exception {
            TicketAgency agency01 = new TicketAgency("窗口1");
            agency01.start();
            TicketAgency agency02 = new TicketAgency("窗口2");
            agency02.start();
            TicketAgency agency03 = new TicketAgency("窗口3");
            agency03.start();
    
        }
    }

    四、线程同步通信问题(外部矛盾)

    我这里所说的线程通信问题 即 2个执行不同任务的线程之间如何完成通信,和以上的线程安全问题不是同1个问题;

    例如:生产者和消费者模式 A生产10件产品,B消费者来消费这10见商品,并保证供需平衡;

    所以A和B阵营主内除了保证自身阵营内部的线程安全,还需要在A和B两个阵营之间建立1种顺序的通信机制;

     A阵营生产完了通知B阵营来消费,B阵营消费完了通知A阵营继续生产;

    1.使用同步代码块

    package zhanggen.com;
    
    //商品类
    public class Product {
        //品牌
        private String band;
        //名字
        private String name;
    
        public Product() {
        }
    
        //set和get方法
        public Product(String band, String name) {
            this.band = band;
            this.name = name;
        }
    
    
        public String getBand() {
            return band;
        }
    
        public String getName() {
            return name;
        }
    
        public void setBand(String band) {
            this.band = band;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    Product

    ---------

    package zhanggen.com;
    
    public class Producer extends Thread {
        //生产的商品
        private Product p;
    
        public Producer(Product p) {
            this.p = p;
        }
    
        @Override
        public void run() {
            //生产10个产品
            for (int i = 1; i <= 10; i++) {
                //利用同步代码块解决供需争抢的问题
                synchronized (p) {
                    if (i % 2 == 0) {
                        //生产费列罗巧克力
                        p.setBand("巧克力");
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
    
                        p.setName("费列罗巧克力");
    
    
                    } else {
                        //生产哈尔滨啤酒
                        p.setBand("啤酒");
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        p.setName("哈尔滨啤酒");
    
                    }
                    //将生产信息做1个打印
                    System.out.printf("生产者生产出: %s品牌 的 %s\r\n", p.getBand(), p.getName());
                }
    
            }
        }
    }
    Producer.java

    --------------

    package zhanggen.com;
    
    //消费者线程
    public class Cousumer extends Thread {
        //共享商品
        private Product p;
    
        Cousumer(Product p) {
            this.p = p;
        }
    
        @Override
        public void run() {//消费者消费10次
            //利用同步代码块解决供需争抢的问题
            synchronized (p) {
                for (int i = 1; i <= 10; i++) {
                    System.out.printf("消费者消费了:%s的%s\n", p.getBand(), p.getName());
                }
            }
    
        }
    }
    Consumer.java

    -----------------

    package zhanggen.com;
    
    public class Market {
        public static void main(String[] args) {
            //共享商品
            Product p = new Product();
            //创建生产者线程
            Producer producer = new Producer(p);
    
            //创建消费者
            Cousumer cousumer = new Cousumer(p);
    
            producer.start();
            cousumer.start();
    
        }
    }
    Market.java

    2.使用同步方法

    package zhanggen.com;
    
    //商品类
    public class Product {
        //品牌
        private String band;
        //名字
        private String name;
    
        public Product() {
        }
    
        //set和get方法
        public Product(String band, String name) {
            this.band = band;
            this.name = name;
        }
    
    
        public String getBand() {
            return band;
        }
    
        public String getName() {
            return name;
        }
    
        public void setBand(String band) {
            this.band = band;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        //利用同步方法解决供需争抢的问题:要么生产!要么消费! 此时调用make锁住的就是谁
        public synchronized void make(int i) {
            if (i % 2 == 0) {
                //生产费列罗巧克力
                this.setBand("巧克力");
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                this.setName("费列罗巧克力");
    
    
            } else {
                //生产哈尔滨啤酒
                this.setBand("啤酒");
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                this.setName("哈尔滨啤酒");
    
            }
            //将生产信息做1个打印
            System.out.printf("生产者生产出: %s品牌 的 %s\r\n", this.getBand(), this.getName());
    
        }
    
    
        //消费
        public synchronized void cost() {
            System.out.printf("消费者消费:%s的%s\n", this.getBand(), this.getName());
    
        }
    
    }
    Product.java

    --------------

    package zhanggen.com;
    
    public class Producer extends Thread {
        private Product p;
    
        public Producer(Product p) {
            this.p = p;
        }
    
    
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                p.make(i);
            }
        }
    }
    Producer.java

    ---------------------

    package zhanggen.com;
    
    //消费者线程
    public class Cousumer extends Thread {
        //共享商品
        private Product p;
    
        Cousumer(Product p) {
            this.p = p;
        }
    
        @Override
        public void run() {//消费者消费10次
            for (int i = 1; i <= 10; i++) {
                p.cost();
            }
    
    
        }
    }
    Consumer.java

    ------------------

    package zhanggen.com;
    
    public class Market {
        public static void main(String[] args) {
            //共享商品
            Product p = new Product();
            //创建生产者线程
            Producer producer = new Producer(p);
    
            //创建消费者
            Cousumer cousumer = new Cousumer(p);
    
            producer.start();
            cousumer.start();
    
        }
    }
    Market.java

    3.wait()和notify()

    在Java对象中有2种池:锁池(synchrnized)和等待池(wait()、notify()、notifyAll())

    如果1个线程对象调用了某个对象的wait()方法,那么该线程进入到该对象的等待池中(并且将锁释放出来,也就是让别的线程先执行。);

    如果未来的某一刻,另外一个线程调用了同一个对象的notify()或者notifyAll()方法,那么等待池中的线程将被唤起,然后进入到对象的锁池里面去获取该对象的锁;

    如果获得锁成功之后,该线程就会沿着wait()方法之后的继续执行。注意是沿着wait()方法之后。

    wait()和notify()必须放在synchronized代码块或者由synchronized修饰的方法内;

    package zhanggen.com;
    
    
    //商品类
    public class Product {
        //品牌
        private String band;
        //名字
        private String name;
    
        //生产和消费指示灯:0正在生产,1可消费
        boolean flag = false;
    
        public Product() {
        }
    
        //set和get方法
        public Product(String band, String name) {
            this.band = band;
            this.name = name;
        }
    
    
        public String getBand() {
            return band;
        }
    
        public String getName() {
            return name;
        }
    
        public void setBand(String band) {
            this.band = band;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        //利用wait和notice进行线程通信,实现多线程同步执行;
        public synchronized void make(int i) {
            //如果消费线程正在消费,生产线程进入等待池。释放锁让给消费线程;
            if (flag == true) {
                try {
                    wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (i % 2 == 0) {
                //生产费列罗巧克力
                this.setBand("巧克力");
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                this.setName("费列罗");
    
    
            } else {
                this.setBand("啤酒");
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                this.setName("哈尔滨");
    
            }
            System.out.printf("生产者生产出%s,品牌为%s\r\n", this.getBand(), this.getName());
            flag = true;
            // 唤醒等待池中的1个消费线程,来消费。
            notify();
        }
    
    
        //利用wait和notice进行线程通信,实现多线程同步执行;
        public synchronized void cost() {
            //如果生产线程正在生产,消费线程进入等待词,让出锁给生产线程;
            if (flag == false) {
                try {
                    wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.printf("消费者消费了%s,品牌为%s\n", this.getBand(), this.getName());
            flag = false;
            //唤醒等待池中的1个生产线程,去生产。
            notify();
    
        }
    
    }

    4.await

    以上我们只是完成1个生产者线程和1个消费者线程之间1对1的顺序通信;

    在JDK1.5之后我们可以使用await()和signal(),实现多个消费者线程 和多个生产者线程之间,多对多通信的顺序通信;

    package zhanggen.com;
    
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //商品类
    public class Product {
        //品牌
        private String band;
        //名字
        private String name;
    
        //生产和消费指示灯:0正在生产,1可消费
        boolean flag = false;
    
        //声明1把Lock锁
        Lock lock = new ReentrantLock();
        //生产者的等待队列
        Condition producersCondition = lock.newCondition();
        //消费者的等待队列
        Condition consumersCondition = lock.newCondition();
    
        public Product() {
        }
    
        //set和get方法
        public Product(String band, String name) {
            this.band = band;
            this.name = name;
        }
    
    
        public String getBand() {
            return band;
        }
    
        public String getName() {
            return name;
        }
    
        public void setBand(String band) {
            this.band = band;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void make(int i) {
            //如果消费线程正在消费,生产线程进入生产者的等待池等待
            lock.lock();
            try {
                if (flag == true) {
                    try {
                        //生产线程进入生产者的等待队列
                        producersCondition.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                if (i % 2 == 0) {
                    this.setBand("巧克力");
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
                    this.setName("费列罗");
    
    
                } else {
                    this.setBand("啤酒");
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    this.setName("哈尔滨");
    
                }
                System.out.printf("生产者生产出%s,品牌为%s\r\n", this.getBand(), this.getName());
                flag = true;
                // 唤醒消费队列中1个消费线程,来消费。
                consumersCondition.signal();
            } finally {
                lock.unlock();
            }
        }
    
    
        public void cost() {
            lock.lock();
    
            try {
                if (flag == false) {
                    try {
                        //消费线程进入消费者的等待队列
                        consumersCondition.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.printf("消费者消费了%s,品牌为%s\n", this.getBand(), this.getName());
                flag = false;
                //唤醒生产者队列中的1个生产线程,去生产
                producersCondition.signal();
    
            } finally {
                lock.unlock();
            }
        }
    
    }

    参考

  • 相关阅读:
    POJ 1887 Testing the CATCHER
    HDU 3374 String Problem
    HDU 2609 How many
    POJ 1509 Glass Beads
    POJ 1458 Common Subsequence
    POJ 1159 Palindrome
    POJ 1056 IMMEDIATE DECODABILITY
    POJ 3080 Blue Jeans
    POJ 1200 Crazy Search
    软件体系结构的艺术阅读笔记1
  • 原文地址:https://www.cnblogs.com/sss4/p/15598507.html
Copyright © 2011-2022 走看看