首页 > 编程语言 >手撕Java多线程(四)线程之间的协作

手撕Java多线程(四)线程之间的协作

时间:2024-03-10 17:14:29浏览次数:31  
标签:Java void wait example 线程 多线程 public before

线程之间的协作

当多个线程可以一起去解决某个问题时,如果某些部分必须在其他部分之前完成,那么就需要对线程进行协调。

join()

在线程中调用另一个线程的join()方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。

对于以下代码,虽然b线程先启动,但是因为在b线程中调用了a线程的join()方法,b线程会等待a线程结束才继续执行,因此最后能够保证a线程的输出先于b线程的输出。

public class JoinExample {

    private class A extends Thread {
        @Override
        public void run() {
            System.out.println("A");
        }
    }

    private class B extends Thread {

        private A a;

        B(A a) {
            this.a = a;
        }

        @Override
        public void run() {
            try {
                a.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B");
        }
    }

    public void test() {
        A a = new A();
        B b = new B(a);
        b.start();
        a.start();
    }
}
public static void main(String[] args) {
    JoinExample example = new JoinExample();
    example.test();
}
A
B

wait() notify() notifyAll()

调用wait()使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其他线程会调用notify()或者notifyAll()来唤醒挂起的线程。

它们都属于Object的一部分,而不属于Thread。

只能用在同步方法或者同步控制块中使用,否则会在运行时抛出IllegalMonitorStateExeception

使用wait()挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行notify()或者notifyAll()来唤醒挂起的线程,造成死锁。

public class WaitNotifyExample {
    public synchronized void before() {
        System.out.println("before");
        notifyAll();
    }

    public synchronized void after() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after");
    }
}
public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    WaitNotifyExample example = new WaitNotifyExample();
    executorService.execute(() -> example.after());
    executorService.execute(() -> example.before());
}
before
after

wait() 和 sleep() 的区别

  • wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
  • wait() 会释放锁,sleep() 不会。

await() signal() signalAll()

java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活。

使用 Lock 来获取一个 Condition 对象。

public class AwaitSignalExample {
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void before() {
        lock.lock();
        try {
            System.out.println("before");
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void after() {
        lock.lock();
        try {
            condition.await();
            System.out.println("after");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    AwaitSignalExample example = new AwaitSignalExample();
    executorService.execute(() -> example.after());
    executorService.execute(() -> example.before());
}
before
after

标签:Java,void,wait,example,线程,多线程,public,before
From: https://www.cnblogs.com/alvisClub/p/18064384

相关文章

  • java.net.UnknownHostException: api.weixin.qq.com解决办法
    java.net.UnknownHostException: api.weixin.qq.comat java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:175)at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384)at java.net.Socket.connect(Socket.java:546)at sun.security.ssl.SSLSo......
  • 学java14用户交互Scanner
    我们可以通过Scanner类来获取用户的输入基本语法Scanners=newScanner(System.in);通过Scanner类的next()与nextLine()方法获取输入的字符串,在读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据。程序实例packageScanner;importjava.util.Scann......
  • 学java13javaDoc生成文档
    找到类的地址,进入类所在文件夹,在导航栏中最前面添加“CMD(空格)”后回车javadoc-encodingUTF-8-charsetUTF-8文件名.java通过idea生成:tools/生成javadoc/第一步:选择生成JavaDoc文档的范围,我只对一个源文件生成Doc,所以选择文件。第二步:输出目录最好新建一个文件......
  • 在Java中,HashMap中是用哪些方法来解决哈希冲突的?
    HashMap中调用hashCode()方法来计算hashCode。由于在Java中两个不同的对象可能有一样的hashCode,所以不同的键可能有一样hashCode,从而导致冲突的产生。采用链地址法解决冲突。HashMap底层是数组+链表+红黑树(JDK1.8)来实现的,根据key的hash值查找对应的位桶。1.当前索引数组为空,则......
  • Java学习笔记——第十一天
    面向对象高级(二)多态多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。多态的具体代码体现//使用同一个类名创建了不同类型的对象,体现了对象多态Peoplep1=newStudent();Peoplep2=newTeacher();//不同类型的对象调用了同一个名字的方法,体现了行为多态p1......
  • Java8新特性
    Java8新特性汇总Java8的改进速度更快代码更少(增加了新的语法:Lambda表达式)引入强大的StreamAPl便于并行最大化减少空指针异常:OptionalNashorn引擎,允许在JVM上运行JS应用并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,......
  • Java泛型
    一、泛型简介1.泛型的概念所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时确定(即传入实际的类型参数,也称为类型实参)。从JDK5.0以后,Ja......
  • Java常用类
    一、String类java.lang.String类的使用(一)概述String:字符串,使用一对""引起来表示。String声明为final的,不可被继承String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小String内部定义了finalchar[]value......
  • IDEA使用与多线程
    IDEA缩写和快捷键psvm全称publicstaticvoidmainsout全称publicstaticvoidmainalt+enter处理异常s.out自动打印sctrl+art+t给整段代码加框如try-catch一、概念进程、程序和进程程序(program)是为完成任务、用某种语言编写的一组指令的集合。即指一段静态的代码,......
  • 辨析Java与网络通信中的编码与解码
    在Java字符流上下文中的编码和解码,以及在网络通信中的编码概念。在Java中,当我们谈论字符流(如Reader和Writer)时,编码和解码主要涉及将字符数据转换为字节数据,以及将字节数据转换回字符数据。这是因为字符在计算机内部是以字节的形式存储和传输的,而字符流提供了一种更高级别的抽象,使......