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

yizhihongxing

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日

相关文章

  • Java集合中的fail-fast(快速失败)机制详解

    Java集合中的fail-fast(快速失败)机制详解 简介 Java集合中的fail-fast机制,指在对集合进行遍历操作的过程中,若集合的结构被修改了(增、删、改),那么程序便会抛出并发修改异常ConcurrentModificationException,终止遍历操作,从而避免因对已经被修改的集合进行操作而导致数据不一致等问题的产生。 fail-fas…

    Java 2023年5月28日
    00
  • Spring使用IOC与DI实现完全注解开发

    这里是使用Spring实现完全注解开发的攻略。 什么是IOC与DI? IOC IOC,全称为Inversion of Control,控制反转,是指将业务逻辑控制转移给容器来处理,由容器通过反射机制去创建或调用对象以及处理对象之间的关系,对于容器是重度依赖的。它实现的方式有两种,分别是Setter注入和构造函数注入。 DI DI,全称为Dependency …

    Java 2023年6月2日
    00
  • java字符串比较获取字符串出现次数的示例

    为了使用 Java 字符串比较获取字符串出现次数,我们需要使用 String 类提供的一些方法。以下是一个实现这个功能的示例代码: public class StringCountExample { public static void main(String[] args) { String str = "Hello World! How are…

    Java 2023年5月27日
    00
  • JavaWeb实现学生信息管理系统(2)

    “JavaWeb实现学生信息管理系统(2)”是一篇教程文章,旨在介绍如何使用JavaWeb技术实现学生信息管理系统。以下是该教程的完整攻略: 简介 在本教程的第一部分中,我们已经搭建好了项目的框架,包括所需的Java类和JSP页面。在本部分中,我们将添加更多的功能来实现完整的学生信息管理系统,并对代码进行相应的优化。 功能实现 添加学生信息 可以通过一个表单…

    Java 2023年5月24日
    00
  • 详解mybatis.generator配上最新的mysql 8.0.11的一些坑

    下面我将详细讲解如何配合最新的MySQL 8.0.11使用MyBatis Generator,并解决可能会遇到的一些坑。具体步骤如下: 1. 准备工作 在开始之前,我们需要准备一些必要的工具和环境: MySQL 8.0.11及以上版本,这里以MySQL 8.0.26为例。 JDK 8及以上版本。 MyBatis Generator,这里以版本1.4.0为例。…

    Java 2023年5月20日
    00
  • Spring-Data-JPA整合MySQL和配置的方法

    下面是Spring-Data-JPA整合MySQL和配置的详细攻略: 1. 添加依赖 首先,在项目的Maven或Gradle配置文件中,添加以下依赖来引入Spring-Data-JPA和MySQL的相关依赖。 Maven: <dependency> <groupId>org.springframework.boot</group…

    Java 2023年5月20日
    00
  • java在运行时能修改工作目录吗

    Java程序在运行时可以修改工作目录,可通过以下方式实现: 使用Java的File类修改工作目录 Java提供了File类来操作文件与目录,通过File类提供的方法可以对现有的目录进行修改。 可以通过以下代码来修改工作目录: File dir = new File("D:\\Java_Project"); System.setProper…

    Java 2023年6月15日
    00
  • 浅谈用java实现事件驱动机制

    浅谈用Java实现事件驱动机制的完整攻略如下: 1. 什么是事件驱动机制 事件驱动是一种编程模型,指的是程序在运行过程中,按照事件或者消息的顺序来触发相应的处理代码,从而完成程序的任务。事件驱动机制通常包括三个主要组成部分:事件源、事件对象以及事件监听器。 2. 事件源、事件对象和事件监听器 事件源是触发事件的源头,是指能够发生某种动作或引起某种状态变化的对…

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