java多线程学习三(线程间的共享和协作)

多线程学习笔记05线程协作 文章目录多线程学习笔记05线程协作线程通信解决方式1管程法解决方式2信号灯法 多线程学习笔记05线程协作 线程通信 应用场景:生产者和消费者问题 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费; 如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止; 如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。 我们来分析一下: 首先,这是一个线程同步问题,生产者和消费者共享同一个资 阅读详情

目录

           ●  yield()和join()方法简介

           ●  线程间的共享

           ●  线程间的协作

yield()和join()方法简介

            yield()方法:使当前线程让出CPU占有权(线程让步),但让出的时间是不可设定的。也不会释放锁资源,所有执行yield()的线程有可能在进入到可执行状态后马上又被执行。

            join()方法:把指定的线程加入到当前线程(线程插队),可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的join()方法,直到线程A执行完毕后,才会继续执行线程B 。

线程间的共享

            java支持多个线程同时访问同一个对象或者对象的成员变量,关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性,又称为内置锁机制。

            对象锁和类锁:对象锁是用于对象实例方法,或者一个对象实例上的。类锁是用于类的静态方法或者一个类的class对象上的额。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以,不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。

            注意:类锁只是一个概念上的东西,并不是真实存在的,类锁其实锁的是每个类的对应的class对象。类锁与对象锁之间也是互不干扰的。

            对象锁的使用:

/**
 * @ author xiaozhou
 * @ Date 2019/4/8
 */
public class SynTest {

    private long count = 0;
    private Object obj = new Object();   //作为一个锁

    /**
     * 下面的三种写法效果是一样的
     */
    public void incCount1() {
        synchronized (obj) {
            //业务逻辑
        }
        
    }

    /**
     * 锁对象
     * 锁的是当前类的实例this
     */
    public synchronized void incCount2() {
         //业务逻辑
    }

    public void incCount3() {
        synchronized (this) {
            //业务逻辑
        }
    }

}

             类锁的使用:

    /**
     * 类锁,实际是锁类的class对象
     */
    private static synchronized void SynClass() {
        SleepTools.second(1);
        System.out.println("synClass going...");
        SleepTools.second(1);
        System.out.println("synClass end...");
    }

    private static Object obj = new Object();
    //因为obj是静态的,在全虚拟机只有一份,所以这里类似于类锁
    private void synStaticObject() {
        synchronized (obj) {   // 类似于类锁
            SleepTools.second(1);
            System.out.println("synClass going...");
            SleepTools.second(1);
            System.out.println("synClass end...");
        }
    }

            代码中已经加了较为详细的注释,所以对此不再做解释。

线程间的协作

            线程之间相互配合,完成某项工作,比如:一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行的又是另外一个线程。前者是生产者,后者就是消费者,这种模式隔离了 “做什么”(what)和 “怎么做”(How),简单的办法是让消费者线程不断地循环检查变量是否符合预期在while循环中设置不满足的条件,如果条件满足则退出while循环,从而完成消费者的工作。(关于对生产者消费者的理解我本打算自己写一篇文章但是在发现一篇文章,让你彻底弄懂生产者--消费者问题之后,我自认为我没有人家理解的透彻,即便写文章也没有人家写的好,所以在此向大家推荐一下,自己也学习了。)但是生产者--消费者模型我认为存在以下两个问题:

           (1)难以确保及时性

           (2)难以降低开销。如果降低睡眠的时间,比如休眠1毫秒,这样消费者能更加迅速地发现条件变化,但是却可能消耗更多的处理器资源,造成了无端的浪费。

等待/通知机制(wait/notify/notifyAll)

           等待/通知是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify()/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。

          1.  wait()

               调用该方法的线程进入waiting状态,只有等待另外线程的通知或被中断才会返回,在调用此方法之前,线程必须要获得该对象的对象监视器锁,所以只能在同步方法或同步代码块中调用wait()方法。调用wait()方法之后当前线程会释放对象的锁。

              wait(long timeout)

               超时等待一段时间,参数是毫秒,也就是等待传入参数的毫秒后,如果没有等到通知或被中断就会超时返回。

              wait(long timeout, int nanos)

               对于超时时间更为精确的控制,第二个参数是纳秒级的。

          2. notify()

              任意从等待在该对象上的线程中挑选一个进行通知,使得调用wait()方法的线程从等待状态切换到就绪状态,等待有机会再次获取到锁,从而使得调用wait()方法的线程能够从wait()方法处退出。调用notify()后,当前线程不会马上释放对象锁,而是要等到程序执行完同步块后,当前线程才会释放锁。没有获取到锁的线程重新进入waiting状态。

          3. notifyAll()

              使所有等待在该对象上的线程从等待状态退出,进入可运行状态。

 

         下面我们通过一个案例来演示wait/notify的使用:

          案例:两个线程一个线程打印1-52的值,另外一个线程打印A-Z的值。

                     打印格式为:12A  34B  56C  78D........

          首先我们来分析一下,根据案例要求,两个线程一个打印数字,一个打印A-Z的字母。好,现在我们一步步来实现:

          1. 首先打印数字的线程实现:

public class Number implements Runnable {

        private Object object;

        public Number(Object obj) {
            this.object = obj;
        }

        @Override
        public void run() {
            synchronized (object) {
                for (int i = 1; i < 53; i++) {
                    //代码块1
                    if (i >= 1 && i % 2 == 1) {
                        System.out.print(" "+i);
                    }
                    //代码块2
                    if (i % 2 == 0) {
                        System.out.print(i);
                        object.notifyAll();
                        try {
                            object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

              我觉得这段代码中需要解释的就是注释中的两个代码块。以下的解释我们都以打印的12A为例。

              代码块1就是做了输出1的逻辑判断,包括后面打印的3、5等都是可以通过这个条件给限定的。

              代码块2就是做了输出2的逻辑判断,这里是能被2整除的数字的输出。输出之后,我们需要通知另外一个线程去做打印字母A的操作,所以这个线程就要调用wait()方法等待另一个线程做完输出字母A的操作之后发出通知再继续按照要求打印数字。

             2. 现在我们来看一下另外一个打印字母的线程的实现。

public class CharacterThread implements Runnable {

    Object object;

    public CharacterThread(Object obj) {
        this.object = obj;
    }

    @Override
    public void run() {
        synchronized (object) {
            for (char i = 'A'; i <= 'Z'; i++) {
                System.out.print(i);
                object.notifyAll();
                try {
                    if (i < 'Z'){
                        object.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

            for循环中首先打印每一个字母,在打印完成后就需要通知打印数字的线程使其下一个数字。所以在打印完一个字母之后当前线程就暂时不能继续打印字母了,需要等到打印数字的线程发送通知过来才能继续打印。当然这些逻辑都是建立在i<'Z'基础之上的。

            3. 然后在Main()方法中调用一下:

public class PrintInfoDemo3 {
    public static void main(String[] args) {
        Object obj = new Object();
        new Thread(new NumberThread(obj)).start();
        new Thread(new CharacterThread(obj)).start();
    }
}

            运行结果:

   证明wait()方法释放锁与notify()不释放锁

   1. wait()方法释放锁:

public class WaitThread implements Runnable {

        private Object obj;

        public WaitThread(Object object) {
            this.obj = object;
        }

        @Override
        public void run() {
            synchronized (obj) {
                try {
                    System.out.println(Thread.currentThread().getName() + "Begin wait()");
                    obj.wait();
                    System.out.println(Thread.currentThread().getName() + "End wait()");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

       main()方法中调用

 public static void main(String[] args) {
        Object object = new Object();
        WaitThread waitThread1 = new WaitThread(object);
        WaitThread waitThread2 = new WaitThread(object);
        new Thread(waitThread1).start();
        new Thread(waitThread2).start();
    }

运行结果是:

如果wait()方法不释放锁,那么Thread-0就不会进入同步代码块中执行打印语句,因此,证明wait()方法是会释放锁的。

2. notify()方法不释放锁的证明

    新建一个线程重写run()方法中的逻辑

public class NotifyThread1 implements Runnable {

        private Object obj;

        public NotifyThread1(Object object) {
            this.obj = object;
        }

        @Override
        public void run() {
            synchronized (obj) {
                try {
                    System.out.println("Begin wait(),ThreadName = " + Thread.currentThread().getName());
                    obj.wait();
                    System.out.println("End wait(), ThreadName = " + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

      再新建一个线程重写run()方法逻辑

 public class NotifyThread2 implements Runnable {

        private Object obj;

        public NotifyThread2(Object object) {
            this.obj = object;
        }

        @Override
        public void run() {
            try {
                synchronized (obj) {
                    System.out.println("Begin notify(), ThreadName = " + Thread.currentThread().getName());
                    obj.notify();
                    Thread.sleep(5000);
                    System.out.println("End notify(), ThreadName = " + Thread.currentThread().getName());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

            然后在main()方法中调用

 public static void main(String[] args) {
        Object object = new Object();
        NotifyThread1 notifyThread1 = new NotifyThread1(object);
        NotifyThread2 notifyThread2 = new NotifyThread2(object);
        new Thread(notifyThread1).start();
        new Thread(notifyThread2).start();
    }

          我们看一下运行结果:

          根据运行结果可以分析:如果notify()方法会释放锁,那么在Thread-1调用notify()后,Thread.sleep(5000)期间一定会有其他线程介入同步代码块,看运行结果分明是等Thread-1休眠完成之后才继续执行的,所以证明notify()方法不能释放锁。

 

这篇文章到这里也就算是完成了,主要介绍了一下线程间的共享和协作。下一篇文章我将继续学习多线程相关的知识。

相关文章阅读

java多线程学习(一)

java多线程学习二(线程的启动和终止)

java多线程学习三(线程间的共享和协作)

 

 

 

 

Java并发编程(4)—— Java多线程的线程间的协作 为了支持多线程之间的协作,JDK 中提供了两个非常重要的方法:wait() 和 notify() ,这两个方法定义在 Object 类中,这意味着任何 Java 对象都可以调用者两个方法。当 object.notify() 方法被调用时,它就会从这个等待队列中随机唤醒一个线程。综上所述可以使用 wait() 和 notify() 配合内部锁 synchronized 可以实现线程间的等待与唤醒,如果你使用的是显示锁而不是内部锁,此时可以使用 Condition 来实现同样的效果。 阅读详情

相关推荐

Java多线程并发:线程间的协作与竞争

在上一期《Java线程优先级:如何影响线程调度》中,我们深入探讨了线程的优先级对调度的影响,分析了不同优先级的线程在CPU资源争夺中的表现。然而,在线程优先级之外,多线程编程的核心在于线程间的协作与竞争。在多线程环境中,多个线程往往需要共享资源,如何有效地进行同步和防止竞态条件是实现高效并发的关键。本期我们将进一步探讨Java多线程并发中线程间的协作与竞争机制,重点介绍线程如何通过协作完成复杂任务,以及如何通过竞争访问共享资源。这些知识将帮助我们更好地理解多线程编程中的挑战,并设计出高效且安全的并发程序。

喵手的博客 1233

Java 如何实现多线程之间的通讯和协作?

Java 如何实现多线程之间的通讯和协作?

javamyfriend的博客 887

Java零基础之多线程篇:线程间如何通信?

随着计算机技术的发展,多线程编程已经成为现代软件开发中的一个重要方向。在多线程编程中,线程间的通信是一个非常关键的问题。在Java开发语言中,Java提供了一些机制来实现线程间的通信,帮助开发者协调不同线程之间的执行顺序和数据交换。本文将介绍Java多线程编程中的线程间通信的相关知识。首先,我们将从简介开始,介绍线程间通信的基本概念和原理。然后,我们将通过源代码解析的方式,深入探讨Java中实现线程间通信的方法。接着,我们将给出一些应用场景案例,展示线程间通信在实际开发中的应用。

喵手的博客 1558

Java线程同步和协作的5种方式

问题:有3个线程为A,B,C,同时启动,C必须等待A和B完成才能继续执行,如何实现?要求:仅使用 java 语言和它原生API使用 Java 中提供的 CountDownLatch 类实现线程之间的同步和协作使用 Java 中提供的 CyclicBarrier 类实现线程之间的同步和协作使用join()方法:Thread类提供了join()方法,可以让一个线程等待另一个线程执行完毕后再继续执行。

qq_42747210的博客 2963

解密Java多线程同步:掌握线程间同步与互斥技巧

在现代软件开发中,多线程是一项重要的技术,而线程间的同步与互斥是其中关键的一部分。本文将揭秘Java多线程同步的奥秘,帮助读者掌握线程间同步与互斥技巧。本文将全面解析Java多线程同步技术,包括线程间通信、锁、条件变量等。我们将深入讨论如何实现线程的同步与互斥,以及应对线程安全问题的技巧。多线程编程中,线程间的同步与互斥是保证数据一致性和程序正确性的关键。在本节中,我们将简要介绍多线程编程的挑战和线程间同步的重要性。在本节中,我们将详细介绍Java中与线程同步相关的类和方法。

喵手的博客 1147

Simulink+Simscape多体仿真:六自由度Stewart平台动力学建模全流程

本文详细介绍了使用Simulink和Simscape Multibody进行六自由度Stewart平台动力学建模的全流程,涵盖从CAD模型导入、运动学逆解计算到实时控制系统的设计。通过MATLAB/Simulink与Simscape的协同工作,实现高保真度的并联机器人仿真,适用于飞行模拟器、精密加工等高精度领域。

r2s3t4的博客 487

Java多线程协作

Java线程同步

zhangyan_1010的专栏 1134

避开这5个坑!Tushare数据获取与清洗的常见问题解决方案

本文详细解析了使用Tushare进行金融数据分析时常见的5大问题,包括Token失效、数据缺失、频率限制等,并提供了Python实战解决方案。通过智能填充策略、队列化管理和分层存储设计,帮助开发者高效获取和清洗金融数据,提升量化分析效率。特别适合金融数据分析师和Python开发者参考。

f9g0h的博客 422

java多线程与线程间通信

本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程的众多常见重要知识点,学习后会对java多线程概念及线程间通信方式有直观清晰的了解和掌握,可以编写并分析简单的多线程程序。 进程与线程 进程:是一个正在执行的程序。 每一个进程执行都有执行顺序,一个执行顺序是一个执行路径,或者叫控制单元; 每一个程序启动时,都会在内存中分配一片空间,进程就用于标识这片空间,并

jerrying0203的专栏 1万+

拆解汽车T-Box:从4G模块到MCU,手把手教你理解车联网的‘黑匣子’

本文深入拆解汽车T-Box,揭示其作为车联网‘黑匣子’的核心架构与工作原理。从4G模块、MCU主控到外设接口,详细解析各组件功能及协同机制,并通过实战案例展示故障诊断与性能优化技巧,帮助读者全面理解T-Box在智能汽车中的关键作用。

weixin_30955617的博客 497

kali虚拟机-----破解wifi密码(WiFi渗透)

文章目录一、将无线网卡挂载到 虚拟机上二、查看是否挂载成功三、查看网卡是否支持监听模式四、检查文件监听影响并杀死影响五、开启无线监听模式六、开始监听七、开始抓包(新建一个命令窗口)八、对已连接的终端进行攻击,使它掉线重连,以此来获取数据包。(新建一个命令窗口)九、开始解密 一、将无线网卡挂载到 虚拟机上 可能出现的问题:在可移动设备处无法连接无线网卡; 解决:在虚拟机设置中将usb控制器设置成如图所示。 注意要先关闭虚拟机在设置。 二、查看是否挂载成功 使用ifconfig命令查看 三、查看网卡是

weixin_46471800的博客 1万+

JAVA学习心得——线程三:线程间的数据共享

并发运行:线程之间互相抢占执行权的状态。 线程中并发指一个时间段中多个线程都处于已启动但没有运行结束的状态。 多个线程之间默认并发运行,这种运行方式往往会出现交叉的情况。 刚开始我很不理解为什么要用串行?多线程的作用不就是把程序并行执行加快运行速度吗? 现在又要将程序串行起来,让程序更加有秩序吗? 串行运行:使原本并发运行的多个线程实现串行运行,即多线程间同步执行,需要通过对象锁机制来实现...

low1101的博客 160

将 AMDP Function Implementations 讲透:从 SAP CDS View 表函数到 AMDP 方法的完整实战与最佳实践

AMDP函数实现:连接ABAP与HANA的高效桥梁 本文面向ABAP开发者,详细解析AMDP函数实现技术,帮助在SAP HANA环境中充分发挥数据库算力。核心内容包括: 技术价值:解决复杂计算场景(窗口函数、跨表聚合等)中Open SQL和CDS的局限性 两种实现类型:内部复用函数与CDS表函数实现,对比其声明规则和用途差异 关键语法要点:FOR TABLE FUNCTION绑定、只读约束、参数与返回类型自动生成机制 实战应用:以采购订单聚合为例,展示AMDP在实时报表中的性能优势 完整示例:提供基于航线数

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 386

Java 多线程学习笔记

*进程:**是操作系统进行资源分配和调度的基本单位,是程序的一次执行过程。**例如:**当你打开一个应用程序,如浏览器、音乐播放器等,操作系统就会为其创建一个进程。**线程:**是进程的一个执行单元,是 CPU 调度和分派的基本单位,一个进程可以包含多个线程。**例如:**在浏览器进程中,可以有多个线程同时运行,例如一个线程负责页面渲染,另一个线程负责网络请求。提高 CPU 利用率,充分利用多核处理器**例如:**下载软件使用多线程可以同时下载多个文件片段,充分利用带宽,提高下载速度。

2301_76962889的博客 2260

C#实战:从零搭建Vosk离线语音转文字系统

本文手把手教你用C#构建离线语音转文字系统,基于NAudio和Vosk实现全流程开发。首先介绍环境搭建,包括NuGet包安装和中文模型配置,强调16kHz单声道音频格式的关键性。接着详细解析音频预处理转换、Vosk模型初始化及识别过程的核心代码,提供多线程优化建议和实时识别扩展思路。文章包含80%以上代码注释,从常见问题排查到性能优化技巧,完整覆盖从"Hello World"到工业级部署的关键技术点,特别适合需要开发本地化语音识别应用的C#开发者。

墨夶的博客 753

100天精通Python(基础篇)——第1天:Python从起源到应用的全面解析(附上Python、PyCharm、VSCode下载安装详细教程)

100天精通Python(基础篇)——第1天:Python从起源到应用的全面解析(附上Python、PyCharm、VSCode下载安装详细教程)

努力让自己发光,对的人才能迎着光而来 101万+

java 学习~多线程通信 使用共享变量 例子和解释

多线程互相通信一般使用共享变量。。 完整验证代码: main 方法 public class Test5 { public static void main(String[] args) { Datax m1=new Datax(); Threadx t1=new Threadx(m1) ; Thready t2= new Thready(m1); t1.start();//就绪,被cpu选中时执行 t2.start(); } } 线程的派生类 1 public c..

qq_57381370的博客 3961

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java多线程编程中的线程间通信

这个示例中使用了两个线程,一个生产者线程和一个消费者线程,它们通过 wait() 和 notify() 方法进行通信。线程池可以有效地管理线程,避免频繁地创建和销毁线程。任务队列用于存储待执行的任务,线程池中的线程可以从队列中取出任务并执行。多个线程需要访问共享的数据,为了避免数据冲突,需要采取合适的同步机制,如锁、信号量等,以确保数据的安全访问。方法,线程可以等待某个条件的满足,然后通知其他线程进行相应的操作。这可以用于线程之间的协调和同步。方法进行通信,实现了线程间的协调和同步。​ 在这个示例中,

Stevedash的博客 225

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JAVA多线程之线程间的通信方式

在分享这篇文字前,我先说一下,我这里有一份Java学习资料,直接加我的Java直播学习群:723197800就能免费领取 本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信 1:同步 这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信 参考示例: 由于线程A和线程B持有同一个MyObject类的对象obj...

weixin_44970764的博客 879

线程间通信

线程间通信

m0_61787196的博客 1774

【多线程】Java多线程学习

Java多线程

qq_37666344的博客 1118

多线程协作机制

JAVA架构师之路 本系列文章均是博主原创,意在记录学习上的知识,同时一起分享学习心得。 第一章 第一节 Java集合总结(架构师之路 ) 第二节 Java多线程(架构师之路 ) 第三节 理解synchronized(架构师之路 ) 文章目录JAVA架构师之路前言一、协作场景二、wait/notify1.wait2.notify3、协作过程三、应用场景3.1 生产者/消费者模式3.2 同时开始3.3 等待结束3.4 异步结果3.5 集合点总结 前言 多线程之间除了竞争关系之外,还存在互相协作的情况。本

qq_23986927的博客 593

45. 【Java】等待与通知:线程间的协作

本文深入讲解Java线程间的等待与通知机制,涵盖wait()/notify()/notifyAll()的基本用法、虚假唤醒问题、Condition接口的灵活应用,以及生产者-消费者模式的实现。通过对比synchronized与ReentrantLock+Condition的差异,帮助开发者掌握线程协作的核心原理,避免常见陷阱,编写高效可靠的多线程程序。

gugucoding的博客 472

java多线程间的通信传值_java多线程与线程间通信

转自(http://blog.youkuaiyun.com/jerrying0203/article/details/45563947)本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程的众多常见重要知识点,学习后会对java多线程概念及线程间通信方式有直观清晰的了解和掌握,可以编写并分析简单的多线程程序。进程与线程进程:是一个正在执行的程序。每一个进程执行都有执行顺序,一个执行顺序是...

weixin_35266799的博客 219
上一篇: java多线程学习二(线程的启动和终止)
下一篇: UML(统一建模语言)扫盲篇
小小幸运儿
博客等级 码龄10年 48粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值