Java线程协作的两种方式小结

Java线程协作是指多个线程之间的相互协作来完成一个任务。在Java中,线程协作有两种方式:wait和notify/notifyAll。

1. wait和notify

当线程需要等待某个条件时,可以调用wait方法。调用wait方法会使线程进入等待状态,直到另一个线程调用notify或notifyAll方法来唤醒它。

示例1:wait和notify的简单使用

下面的代码演示了wait和notify的简单使用方式:

public class WaitNotifyDemo {
    public static void main(String[] args) throws InterruptedException{
        Object lock = new Object();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                synchronized(lock) {
                    try {
                        System.out.println("Thread 1 is waiting");
                        lock.wait();
                        System.out.println("Thread 1 is awake");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                synchronized(lock) {
                    System.out.println("Thread 2 is running");
                    lock.notify();
                }
            }
        });

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

这个例子中,有两个线程t1t2,它们共享了一个锁对象lock。线程t1在同步代码块中调用了lock.wait()方法,会使它进入等待状态。线程t2在同步代码块中调用了lock.notify()方法,唤醒了处于等待状态中的线程t1。程序输出结果为:

Thread 1 is waiting
Thread 2 is running
Thread 1 is awake

可以看到,线程t1等待了一段时间后被唤醒,才继续向下执行。

示例2:wait和notify解决生产者消费者问题

下面的代码使用wait和notify解决了生产者消费者问题:

public class ProducerConsumerDemo {
    private static final int MAX_SIZE = 10;
    private List<Integer> list = new ArrayList<Integer>();

    public static void main(String[] args) {
        ProducerConsumerDemo demo = new ProducerConsumerDemo();
        demo.start();
    }

    public void start() {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.start();
        consumer.start();
    }

    private class Producer implements Runnable {
        public void run() {
            while (true) {
                synchronized (list) {
                    while (list.size() >= MAX_SIZE) {
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    int val = (int) (Math.random() * 100);
                    list.add(val);
                    System.out.println(Thread.currentThread().getName() + ": produce " + val);
                    list.notifyAll();
                }
            }
        }
    }

    private class Consumer implements Runnable {
        public void run() {
            while (true) {
                synchronized (list) {
                    while (list.size() == 0) {
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    int val = list.remove(0);
                    System.out.println(Thread.currentThread().getName() + ": consume " + val);
                    list.notifyAll();
                }
            }
        }
    }

}

这个例子中,有一个ProducerConsumerDemo类,它有一个共享的list变量,用来存放生产者生产的数据。Producer类实现了生产者的功能,Consumer类实现了消费者的功能。在Producer类中,当list中的元素数量达到最大值MAX_SIZE时,会调用list.wait()方法让该线程进入等待状态,一直到Consumer类消耗掉list中的元素后,唤醒它。在Consumer类中,当list为空时,会调用list.wait()方法让该线程进入等待状态,一直到Producer类生产出新的元素后,唤醒它。程序输出结果为:

Thread-0: produce 81
Thread-1: consume 81
Thread-0: produce 87
Thread-1: consume 87
Thread-0: produce 25
Thread-1: consume 25
...

可以看到,生产者和消费者之间实现了协作,生产者在list中存放数据,消费者从list中取走生产者生产的数据,生产者消费者的数量达到了平衡。

2. park和unpark

JDK1.5新增了Lock对象和Condition接口,其中Condition的await()方法是park的封装,signal()方法是unpark的封装。

示例1:park和unpark的简单使用

下面的代码演示了park和unpark的简单使用方式:

public class ParkUnparkDemo {
    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                lock.lock();
                try {
                    System.out.println("Thread 1 is waiting");
                    condition.await();
                    System.out.println("Thread 1 is awake");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                lock.lock();
                try {
                    System.out.println("Thread 2 is running");
                    condition.signal();
                } finally {
                    lock.unlock();
                }
            }
        });

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

这个例子中,有两个线程t1t2,它们共享了一个Lock对象和一个Condition对象。线程t1在同步代码块中调用了condition.await()方法,会使它进入等待状态。线程t2在同步代码块中调用了condition.signal()方法,唤醒了处于等待状态中的线程t1。程序输出结果为:

Thread 1 is waiting
Thread 2 is running
Thread 1 is awake

可以看到,线程t1等待了一段时间后被唤醒,才继续向下执行。

示例2:park和unpark解决生产者消费者问题

下面的代码使用park和unpark解决了生产者消费者问题:

public class ProducerConsumerDemo1 {
    private static final int MAX_SIZE = 10;

    private Lock lock = new ReentrantLock();

    private Condition notFull = lock.newCondition();

    private Condition notEmpty = lock.newCondition();

    private LinkedList<Integer> list = new LinkedList<Integer>();

    public static void main(String[] args) {
        ProducerConsumerDemo1 demo = new ProducerConsumerDemo1();
        demo.start();
    }

    public void start() {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.start();
        consumer.start();
    }

    private class Producer implements Runnable {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (list.size() >= MAX_SIZE) {
                        notFull.await();
                    }
                    int val = (int) (Math.random() * 100);
                    list.add(val);
                    System.out.println(Thread.currentThread().getName() + ": produce " + val);
                    notEmpty.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    private class Consumer implements Runnable {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (list.size() == 0) {
                        notEmpty.await();
                    }
                    int val = list.removeFirst();
                    System.out.println(Thread.currentThread().getName() + ": consume " + val);
                    notFull.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}

这个例子中,有一个ProducerConsumerDemo1类,它有一个共享的list变量,用来存放生产者生产的数据。Producer类实现了生产者的功能,Consumer类实现了消费者的功能。在Producer类中,当list中的元素数量达到最大值MAX_SIZE时,会调用notFull.await()方法让该线程进入等待状态,一直到Consumer类消耗掉list中的元素后,唤醒它。在Consumer类中,当list为空时,会调用notEmpty.await()方法让该线程进入等待状态,一直到Producer类生产出新的元素后,唤醒它。程序输出结果为:

Thread-0: produce 19
Thread-1: consume 19
Thread-0: produce 87
Thread-1: consume 87
Thread-0: produce 74
Thread-1: consume 74
...

可以看到,生产者和消费者之间实现了协作,生产者在list中存放数据,消费者从list中取走生产者生产的数据,生产者消费者的数量达到了平衡。

以上就是Java线程协作的两种方式的完整攻略,希望能对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java线程协作的两种方式小结 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • 关于Springboot+gateway整合依赖并处理依赖冲突问题

    这里给您详细讲解一下关于Springboot+gateway整合依赖并处理依赖冲突问题的完整攻略。 1. 新建Spring Boot项目 在你的IDE中(如:IntelliJ IDEA或Eclipse),选择File -> New -> Project,选择Spring Initializr创建一个Maven项目,选择Web, Gateway依赖…

    Java 2023年5月20日
    00
  • mybatis原理概述入门教程

    介绍 MyBatis是一种持久层框架,它允许你使用普通SQL查询、存储过程和高级映射,以及高级映射的结果集和连接。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及缓存代码的需求。MyBatis可以与Spring框架集成。 MyBatis原理概述包括以下方面: 1.配置文件 2.映射文件 3.会话工厂 4.SqlSessionFactoryBui…

    Java 2023年5月20日
    00
  • 如何使用Java运行期注解?

    准备工作: 在本地电脑上安装Java开发环境,确保可以运行Java程序。 Step 1:定义注解 在Java中,定义注解需要使用@interface关键字,如下所示: public @interface MyAnnotation { String value(); } 其中,@interface是用来声明一个注解的关键字,MyAnnotation是注解的名称…

    Java 2023年5月11日
    00
  • Java实例化类详解

    Java实例化类详解 在Java中,实例化类是创建类对象的过程。当我们创建一个类对象的时候,就可以使用该类所定义的方法和属性。 实例化类的基础知识 我们可以使用 new 关键字来创建一个类的实例,其基本语法如下: ClassName obj = new ClassName(); 其中,ClassName 是需要创建实例的类名,obj 是创建的对象名。在创建对…

    Java 2023年5月26日
    00
  • 标记-复制算法的作用是什么?

    以下是关于标记-复制算法的详细讲解: 什么是标记-复制算法? 标记-复制算法是一种常见的垃圾回收算法。它的原理是将内存空间分为两个区域,一部分为活动区,一部分为闲置区。在程序运行程中,标记所有不再使用的内存空间,然后将所有活动区的对象复制到闲置区,最后清空动区,从而回收内存空间。标记-复制算法分两个阶段:标记阶段和复制阶段。 记段在标记阶段,垃圾回收器会遍历…

    Java 2023年5月12日
    00
  • eclipse maven 插件的安装和配置详解

    下面是“eclipse maven 插件的安装和配置详解”的完整攻略。 安装Eclipse Maven插件 打开Eclipse并切换到“Help”菜单,选择“Eclipse Marketplace”选项。 在“Eclipse Marketplace”搜索栏中输入“Maven”,然后点击“Go”按钮进行搜索。 在搜索结果中,找到“Maven Integrati…

    Java 2023年5月20日
    00
  • Java SpringBoot 中的操作事务

    我们来详细讲解一下Java SpringBoot中的操作事务。 什么是事务 事务是指作为单个逻辑工作单元执行的一系列操作,这些操作要么全部执行,要么全部不执行,如果在执行整个事务时发生错误,会回滚到事务的开始状态,使所有操作都回到事务执行之前的状态。 Spring 中如何使用事务 Spring 提供了一套完整的事务管理机制,其中最基础的是PlatformTr…

    Java 2023年5月19日
    00
  • Java实现ATM机操作系统

    Java实现ATM机操作系统攻略 ATM机是我们日常生活中使用的一种非常常见的机器,它可以进行银行卡的存取款、查询账户余额等一系列操作。通过Java实现ATM机的操作系统,可以更加深入地学习Java语言以及面向对象编程的核心思想,同时也能够提高编程能力与实际项目开发经验。 1. 系统需求分析 在实现ATM机操作系统之前,首先需要进行系统需求分析,包括系统所需…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部