彻底明白JAVA的多线程 线程间的通信
java 线程间通信的几种方法
java 线程间通信的几种方法Java是一种广泛使用的编程语言,多线程是其重要的特性之一。
在多线程编程中,线程间通信是一种常见的需求。
线程间通信指的是多个线程之间通过共享的对象来传递信息或者协调任务的执行。
本文将介绍Java中线程间通信的几种常用方法。
1. 共享变量共享变量是最简单、最常见的线程间通信方式。
多个线程可以通过读写共享变量来进行通信。
在Java中,可以使用volatile关键字来保证共享变量的可见性,即一个线程对共享变量的修改对其他线程是可见的。
此外,可以使用synchronized关键字来实现对共享变量的互斥访问,保证线程安全。
2. wait()和notify()wait()和notify()是Java中Object类的两个方法,也是实现线程间通信的经典方式。
wait()方法使当前线程等待,直到其他线程调用了相同对象的notify()方法唤醒它。
notify()方法用于唤醒等待的线程。
这种方式需要借助于synchronized关键字来实现线程间的同步。
3. ConditionCondition是Java中提供的一个高级线程间通信工具,它可以在某个条件满足时唤醒等待的线程。
Condition对象需要与Lock对象配合使用,通过Lock对象的newCondition()方法创建。
Condition提供了await()、signal()和signalAll()等方法,分别用于线程等待、单个线程唤醒和全部线程唤醒。
4. CountDownLatchCountDownLatch是Java并发包中的一个工具类,它可以实现线程间的等待。
CountDownLatch内部维护了一个计数器,线程调用await()方法会等待计数器归零,而其他线程调用countDown()方法会使计数器减一。
当计数器归零时,等待的线程会被唤醒。
5. BlockingQueueBlockingQueue是Java并发包中提供的一个阻塞队列,它实现了生产者-消费者模式。
Java多线程编程详解
J a v a多线程编程详解一:理解多线程多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。
线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。
多个线程的执行是并发的,也就是在逻辑上“同时”,而不管是否是物理上的“同时”。
如果系统只有一个CPU,那么真正的“同时”是不可能的,但是由于CPU的速度非常快,用户感觉不到其中的区别,因此我们也不用关心它,只需要设想各个线程是同时执行即可。
多线程和传统的单线程在程序设计上最大的区别在于,由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的,由此带来的线程调度,同步等问题,将在以后探讨。
二:在Java中实现多线程我们不妨设想,为了创建一个新的线程,我们需要做些什么?很显然,我们必须指明这个线程所要执行的代码,而这就是在Java中实现多线程我们所需要做的一切!真是神奇!Java是如何做到这一点的?通过类!作为一个完全面向对象的语言,Java提供了类来方便多线程编程,这个类提供了大量的方法来方便我们控制自己的各个线程,我们以后的讨论都将围绕这个类进行。
那么如何提供给Java 我们要线程执行的代码呢?让我们来看一看Thread 类。
Thread 类最重要的方法是run() ,它为Thread 类的方法start() 所调用,提供我们的线程所要执行的代码。
为了指定我们自己的代码,只需要覆盖它!方法一:继承Thread 类,覆盖方法run()我们在创建的Thread 类的子类中重写run() ,加入线程所要执行的代码即可。
下面是一个例子:public class MyThread extends Thread {int count= 1, number;public MyThread(int num) {number = num;"创建线程" + number);}public void run() {while(true) {"线程" + number + ":计数" + count);if(++count== 6) return;}}public static void main(String args[]) {for(int i = 0; i < 5; i++) new MyThread(i+1).start();}}这种方法简单明了,符合大家的习惯,但是,它也有一个很大的缺点,那就是如果我们的类已经从一个类继承(如小程序必须继承自Applet 类),则无法再继承Thread 类,这时如果我们又不想建立一个新的类,应该怎么办呢?我们不妨来探索一种新的方法:我们不创建Thread 类的子类,而是直接使用它,那么我们只能将我们的方法作为参数传递给Thread 类的实例,有点类似回调函数。
java线程间通信的几种方法
java线程间通信的几种方法在并发编程中,线程间通信是一个非常重要的部分,因为线程间通信会保证一致性和完整性,并且能满足复杂的要求。
在Java编程中,也存在多种线程通信的方法,其中包括变量共享、消息传递、锁定机制和信号量机制等。
首先,对于变量共享,它是一种最简单的线程通信方法。
Java 内存模型确保,所有的线程都可以访问其他线程定义的共享变量,从而满足线程间通信的需求。
变量共享比较灵活,适用于简单的线程间通信,但缺点是无法解决复杂的线程间同步问题。
其次,消息传递是一种灵活的线程间通信方法。
它可以实现不同线程之间传递信息,但不会影响它们之间的执行顺序,也可以用来处理复杂的线程同步问题。
Java提供了隐式和显式的消息传递API,其中最常见的是 wait() notify()法。
紧接着,锁定机制是另一种常见的线程通信方法。
Java程序提供了两种锁,分别是同步块和同步方法,这两种锁都可以用来实现线程间的同步。
这种机制非常有效,但是需要程序员谨慎使用,以免出现死锁等问题。
最后,信号量机制是另一种常用的线程间通信方法。
它可以让多个线程同步执行,从而实现线程间的同步。
它的实现原理是,使用信号量计数器来跟踪有多少线程在排队等待共享资源,当所有的线程都完成之后,再将其中一个线程放到资源中,然后将信号量计数器减1,以此类推。
以上就是Java线程间通信的几种方法。
每种方法都有它特有的优点和缺点,在实际应用中,应根据实际情况选择最合适的线程通信方法。
在编程时,应尽量避免使用复杂的锁机制,如果非要使用,则需要谨慎处理,以免出现死锁等问题。
如果需要处理复杂的线程间同步问题,消息传递是一种不错的方法。
此,在实际开发中,应尽可能地使用最适合的线程通信方法,以节省开发时间和精力,提高开发效率。
谈谈你对Java多线程的理解以及多线程的实现方式
谈谈你对Java多线程的理解以及多线程的实现⽅式说线程之前先说进程,何为进程?进程就是正在进⾏中的程序.⽐如电脑同时在运⾏QQ进程、cmd进程、wps进程、飞秋进程等。
在某⼀时刻,CPU只能执⾏⼀个程序,只是在做快速切换,我们⾁眼看不出来。
⽐如:我有⼀些箱⼦,我⼀个⼈去搬,搬了⼀个⼜⼀个,很累,如果有5个⼈⼀起搬,就更快了5个⼈同时去搬都在⼀个进程中完成,这5个⼈叫线程,线程是进程中的内容。
进程:是⼀个正在执⾏中的程序每⼀个进程执⾏都有⼀个执⾏顺序,该顺序是⼀个执⾏路径,或者叫⼀个控制单元。
线程:就是进程中的⼀个独⽴的控制单元。
线程在控制着进程的执⾏。
⼀个进程中⾄少有⼀个线程,⾄少有⼀个控制单元。
java VM 启动的时候会有⼀个进程java.exe,该进程中⾄少有⼀个线程负责Java程序的执⾏⽽且这个线程运⾏的代码存在于main⽅法中,该线程称之为主线程。
JVM启动不⽌⼀个线程,还有负责垃圾回收机制的线程。
任何⼀个代码执⾏的时候都会进内存,线程的控制单元依次往下执⾏,⽽负责执⾏的代码都在线程。
线程的出现让我们的程序有同时出现的效果,多线程能帮我们提⾼效率,⽬的在于能使多个代码同时运⾏。
线程是程序中的执⾏线程,Java虚拟机允许应⽤程序并发的运⾏多个线程每个线程都有⼀个优先级,⾼优先级线程的执⾏优于低优先级的线程。
当某个线程中运⾏的代码创建⼀个新Thread对象时,该线程的初始优先级被设定为创建线程的优先级。
从语义上去理解,想成为异常就继承exception,想成为线程就继承Thread,成为我的⼩弟你就是我的了,你就拥有了我所有⽤的属性及⽅法了。
那么如何在代码中⾃定义⼀个线程?通过对api的查找,Java已经提供了对线程这类事务的描述,就是Thread类创建线程的第⼀种⽅式:继承Thread类步骤:1、定义类继承Thread2、覆写Thread类中的run⽅法3、调⽤该⽅法:调⽤线程的start⽅法该⽅法有两个作⽤:启动线程,调⽤run⽅法new⼀个对象就是在创建线程,创建了之后并没有执⾏,所以要调⽤start⽅法才能被执⾏那怎么执⾏呢?调⽤run⽅法⽽:可以看到,执⾏顺序会乱,⽽且每次运⾏的结果都不同。
线程间通信的几种方法java
一、概述线程是多任务处理中的一个重要概念,而线程间通信则是在多个线程处理不同任务的情况下,需要进行数据共享和交流的重要问题。
在Java语言中,线程间通信的方式有多种,本文将对几种常用的线程间通信方法进行介绍和分析。
二、共享内存1. 共享内存是一种通过在多个线程之间共享变量来进行通信的方式。
在Java中,可以使用共享变量来实现线程间通信,例如使用volatile关键字进行变量的共享。
2. 共享内存的优点是实现简单,但在多线程并发操作时会导致数据不一致问题,需要谨慎处理同步和顺序性的问题。
三、管程(Monitor)和synchronized关键字1. 管程是一种通过对象的加锁和解锁来进行线程间通信的方式。
在Java中,可以使用synchronized关键字对共享对象进行加锁和解锁,实现线程间的同步和互斥操作。
2. 管程的优点是可以有效解决共享变量操作的同步和顺序性问题,但在使用synchronized关键字时需要注意避免死锁和性能问题的发生。
四、w本人t()、notify()和notifyAll()方法1. w本人t()、notify()和notifyAll()是Object类中定义的几种用于线程间通信的方法。
2. w本人t()方法可以让线程等待,并释放对象的锁;notify()方法可以唤醒一个等待的线程;notifyAll()方法可以唤醒所有等待的线程。
3. 使用w本人t()、notify()和notifyAll()方法可以实现线程间的协作和通信,但需要注意避免虚假唤醒和线程安全问题。
五、并发队列(ConcurrentQueue)1. 并发队列是一种通过队列数据结构来实现线程安全的共享对象,通常用于生产者-用户模式的线程间通信。
2. Java中提供了ConcurrentLinkedQueue和BlockingQueue等并发队列实现,可以实现多线程间的数据交换和共享,避免了手动同步和加锁的操作。
六、信号量(Semaphore)和倒计数器(CountDownLatch)1. 信号量和倒计数器是两种用于控制并发线程执行顺序和数量的同步工具。
java多线程知识点
java多线程知识点
Java多线程是Java编程中的重要概念之一,它允许程序在同一时间内执行多个线程。
下面是Java多线程的一些知识点:
1. 线程的创建:Java中线程的创建可以使用Thread类或者实现Runnable接口来创建。
2. 线程的状态:Java中线程有5种状态,包括新建状态、就绪状态、运行状态、阻塞状态和死亡状态。
3. 线程的同步:Java中提供了synchronized关键字来实现线程同步,还可以使用Lock接口来实现线程的同步操作。
4. 线程池:Java中的线程池是一组预先创建好的线程,可以重复使用,避免了线程的创建和销毁带来的性能开销。
5. 线程间的通信:Java中线程间的通信可以使用wait()、notify()和notifyAll()方法来实现。
6. 线程安全:Java中线程安全是指多个线程同时访问同一资源时,不会发生数据冲突或者数据不一致的问题。
7. 线程调度:Java中的线程调度是由操作系统来完成的,它会按照一定的策略来分配CPU资源。
8. 线程的优先级:Java中线程的优先级分为1-10级,数值越大表示优先级越高。
以上就是Java多线程的一些核心知识点,了解这些知识点对于进行Java多线程编程是非常有帮助的。
- 1 -。
java 线程间通信的几种方法
java线程间通信的几种方法在Java多线程编程中,线程间的通信是非常重要的一个方面。
线程间通信可以使多个线程协同工作,实现资源共享和数据交换。
本文将介绍几种Java线程间通信的方法,帮助读者理解和应用线程间通信的原理和技巧。
正文1. 共享变量共享变量是最基本的线程间通信方法之一。
多个线程可以通过共享变量来交换信息。
在Java中,线程之间可以访问同一个对象的成员变量,通过修改共享变量的值来实现线程间的通信。
需要注意的是,当多个线程同时访问共享变量时,必须确保线程安全,避免出现竞态条件。
2. wait()和notify()wait()和notify()是Java语言提供的线程间通信方法。
wait()方法可以使当前线程等待,直到其他线程调用同一个对象的notify()方法唤醒它。
通过在共享对象上调用wait()和notify()方法,可以实现线程之间的协调和通信。
需要注意的是,wait()和notify()方法必须在synchronized代码块中使用,并且只能在同一个对象上进行。
3. join()join()方法可以用于等待其他线程的结束。
调用线程的join()方法会使当前线程进入等待状态,直到被等待线程执行完毕。
通过join()方法,可以实现线程之间的顺序执行和结果的合并。
4. ConditionCondition是Java并发包中的一个重要组件,用于实现更加灵活的线程间通信。
Condition可以通过await()和signal()方法来实现线程的等待和唤醒。
与wait()和notify()相比,Condition提供了更加灵活的线程间通信方式,可以实现多个条件的等待和唤醒。
5. 信号量(Semaphore)信号量是一种计数器,用来控制同时访问某个资源的线程个数。
通过信号量,可以实现线程之间的互斥和同步。
在Java中,可以使用Semaphore类来实现信号量。
通过acquire()和release()方法,可以控制信号量的获取和释放。
线程之间的通信(threadsignal)
线程之间的通信(threadsignal)线程通信的⽬的是为了能够让线程之间相互发送信号。
另外,线程通信还能够使得线程等待其它线程的信号,⽐如,线程B可以等待线程A 的信号,这个信号可以是线程A已经处理完成的信号。
通过共享对象通信有⼀个简单的实现线程之间通信的⽅式,就是在共享对象的变量中设置信号值。
⽐如线程A在⼀个同步块中设置⼀个成员变量hasDataToProcess值为true,⽽线程B同样在⼀个同步块中读取这个成员变量。
下⾯例⼦演⽰了⼀个持有信号值的对象,并提供了设置信号值和获取信号值的同步⽅法:public class MySignal {private boolean hasDataToProcess;public synchronized void setHasDataToProcess(boolean hasData){this.hasDataToProcess=hasData;}public synchronized boolean hasDataToProcess(){return this.hasDataToProcess;}}ThreadB计算完成会在共享对象中设置信号值:public class ThreadB extends Thread{int count;MySignal mySignal;public ThreadB(MySignal mySignal){this.mySignal=mySignal;}@Overridepublic void run(){for(int i=0;i<100;i++){count=count+1;}try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}mySignal.setHasDataToProcess(true);}}ThreadA在循环中⼀直检测共享对象的信号值,等待ThreadB计算完成的信号:public class ThreadA extends Thread{MySignal mySignal;ThreadB threadB;public ThreadA(MySignal mySignal, ThreadB threadB){this.mySignal=mySignal;this.threadB=threadB;}@Overridepublic void run(){while (true){if(mySignal.hasDataToProcess()){System.out.println("线程B计算结果为:"+threadB.count);break;}}}public static void main(String[] args) {MySignal mySignal=new MySignal();ThreadB threadB=new ThreadB(mySignal);ThreadA threadA=new ThreadA(mySignal,threadB);threadB.start();threadA.start();}}很明显,采⽤共享对象⽅式通信的线程A和线程B必须持有同⼀个MySignal对象的引⽤,这样它们才能彼此检测到对⽅设置的信号。
Java面试--线程之间是如何通信
Java⾯试--线程之间是如何通信Java⾯试--线程之间是如何通信线程之间为什么要进⾏通信线程是操作系统调度的最⼩单位,有⾃⼰的栈(JVM中的虚拟机stack)空间,可以按照既定的代码逐步的执⾏,但是如果每个线程间都孤⽴的运⾏,那就会造资源浪费。
所以在现实中,我们需要这些线程间可以按照指定的规则共同完成⼀件任务,所以这些线程之间就需要互相协调,这个过程被称为线程的通信。
多个线程并发执⾏时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成⼀件任务,并且我们希望他们有规律的执⾏, 那么多线程之间需要⼀些协调通信,以此来帮我们达到多线程共同操作⼀份数据。
当然如果我们没有使⽤线程通信来使⽤多线程共同操作同⼀份数据的话,虽然可以实现,但是在很⼤程度会造成多线程之间对同⼀共享变量的争夺,那样的话势必为造成很多错误和损失!所以,我们才引出了线程之间的通信,多线程之间的通信能够避免对同⼀共享变量的争夺。
线程的通信可以被定义为:线程通信就是当多个线程共同操作共享的资源时,互相告知⾃⼰的状态以避免资源争夺。
线程通信的⽅式线程通信主要可以分为三种⽅式,分别为共享内存、消息传递(也叫等待-通知)和管道流。
每种⽅式有不同的⽅法来实现。
在Java中线程之间的通信⽅式总共有8种,分别是:volatile、synchronized、interrupt、wait、notify、notifyAll、join、管道输⼊/输出共享内存:线程之间共享程序的公共状态,线程之间通过读-写内存中的公共状态来隐式通信。
⽐如 volatile 保证内存的可见性。
消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显⽰的进⾏通信。
⽐如 wait/notify/notifyAll等待通知⽅式和join⽅式。
多个线程在处理同⼀个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同⼀个变量的使⽤或操作。
就是多个线程在操作同⼀份数据时,避免对同⼀共享变量的争夺。
java多线程原理
java多线程原理Java多线程原理。
Java作为一种面向对象的编程语言,具有强大的多线程支持,允许程序同时执行多个任务,提高了程序的运行效率。
本文将深入探讨Java多线程的原理,帮助读者更好地理解和应用多线程技术。
在Java中,多线程是通过Thread类来实现的。
每个线程都有自己的执行路径,可以独立执行不同的任务。
在多线程编程中,需要注意线程间的同步与互斥,以避免出现数据竞争和死锁等问题。
Java多线程的原理主要包括以下几个方面:1. 线程的创建和启动。
在Java中,可以通过继承Thread类或实现Runnable接口来创建线程。
然后调用start()方法来启动线程,使其进入就绪状态,等待CPU调度执行。
2. 线程的调度和执行。
Java的线程调度由操作系统来完成,根据线程的优先级和调度策略来确定哪个线程优先执行。
在多核处理器上,多个线程可以同时执行,提高了程序的并发性能。
3. 线程的同步与互斥。
多个线程访问共享资源时,需要进行同步操作,以避免数据的不一致性。
Java提供了synchronized关键字和Lock接口来实现线程的同步和互斥。
4. 线程的通信。
线程间需要进行通信和协调,以实现任务的合作和数据的交换。
Java提供了wait()、notify()和notifyAll()方法来实现线程的等待和唤醒。
5. 线程的生命周期管理。
线程的生命周期包括新建、就绪、运行、阻塞和死亡等状态。
Java提供了Thread类的方法来管理线程的状态转换和生命周期控制。
在实际应用中,Java多线程可以应用于网络编程、并发处理、图形界面等领域,提高了程序的响应速度和用户体验。
但是多线程编程也存在一些问题,如线程安全、性能损耗和调试困难等,需要程序员进行深入的理解和掌握。
总的来说,Java多线程原理涉及了线程的创建、调度、同步、通信和生命周期管理等方面,是Java编程中的重要知识点。
掌握了多线程原理,可以更好地利用Java的并发特性,提高程序的性能和可靠性,实现更复杂的应用场景。
java多线程5:线程间的通信
java多线程5:线程间的通信在多线程系统中,彼此之间的通信协作⾮常重要,下⾯来聊聊线程间通信的⼏种⽅式。
wait/notify想像⼀个场景,A、B两个线程操作⼀个共享List对象,A对List进⾏add操作,B线程等待List的size=500时就打印记录⽇志,这要怎么处理呢?⼀个办法就是,B线程while (true) { if(List.size == 500) {打印⽇志} },这样两个线程之间就有了通信,B线程不断通过轮训来检测 List.size == 500 这个条件。
这样可以实现我们的需求,但是也带来了问题:CPU把资源浪费了B线程的轮询操作上,因为while操作并不释放CPU资源,导致了CPU会⼀直在这个线程中做判断操作。
这要⾮常浪费CPU资源,所以就需要有⼀种机制来实现减少CPU的资源浪费,⽽且还可以实现在多个线程间通信,它就是“wait/notify”机制。
定义两个线程类:public class MyThread1_1 extends Thread {private Object lock;public MyThread1_1(Object lock) {this.lock = lock;}public void run() {try {synchronized (lock) {System.out.println(Thread.currentThread().getName() + "开始------wait time = " + System.currentTimeMillis());lock.wait();System.out.println(Thread.currentThread().getName() + "开始------sleep time = " + System.currentTimeMillis());Thread.sleep(2000);System.out.println(Thread.currentThread().getName() + "结束------sleep time = " + System.currentTimeMillis());System.out.println(Thread.currentThread().getName() + "结束------wait time = " + System.currentTimeMillis());}} catch (InterruptedException e) {e.printStackTrace();}}}public class MyThread1_2 extends Thread {private Object lock;public MyThread1_2(Object lock) {this.lock = lock;}public void run() {try {synchronized (lock) {System.out.println(Thread.currentThread().getName() + "开始------notify time = " + System.currentTimeMillis());lock.notify();System.out.println(Thread.currentThread().getName() + "开始------sleep time = " + System.currentTimeMillis());Thread.sleep(2000);System.out.println(Thread.currentThread().getName() + "结束------sleep time = " + System.currentTimeMillis());System.out.println(Thread.currentThread().getName() + "结束------notify time = " + System.currentTimeMillis());}} catch (Exception e) {e.printStackTrace();}}} 测试⽅法,myThread1先执⾏,然后sleep ⼀秒后,myThread2再执⾏@Testpublic void test1() throws InterruptedException {Object object = new Object();MyThread1_1 myThread1_1 = new MyThread1_1(object);MyThread1_2 myThread1_2 = new MyThread1_2(object);myThread1_1.start();Thread.sleep(1000);myThread1_2.start();myThread1_1.join();myThread1_2.join();} 执⾏结果:Thread-0开始------wait time = 1639464183921Thread-1开始------notify time = 1639464184925Thread-1开始------sleep time = 1639464184925Thread-1结束------sleep time = 1639464186928Thread-1结束------notify time = 1639464186928Thread-0开始------sleep time = 1639464186928Thread-0结束------sleep time = 1639464188931Thread-0结束------wait time = 1639464188931 可以看到第⼀⾏和第⼆⾏开始执⾏之间只间隔了1s,说明wait⽅法确实进⼊等待,⽽且没有继续执⾏wait后⾯的sleep 2秒,⽽是执⾏了notify⽅法,说明wait⽅法可以使调⽤该⽅法的线程释放共享资源的锁,然后从运⾏状态退出,进⼊等待队列,直到被再次唤醒。
彻底明白Java的多线程-线程间的通信
一.实现多线程1. 虚假的多线程例1:publicclassTestThread{inti=0, j=0;publicvoidgo(intflag){while(true){try{java/lang/Thread.java.html" target="_blank">Thread.sleep(100);}catch(java/lang/InterruptedException.java.html" target="_blank"> InterruptedExceptione){java/lang/System.java.html" target="_blank">System.out.println("Interrupted");}if(flag==0)i++;java/lang/System.java.html" target="_blank">System.out.println("i=" + i);}else{j++;java/lang/System.java.html" target="_blank">System.out.println("j=" + j);}}}publicstaticvoidmain(java/lang/String.java.html" target="_blank"> String[] args){newTestThread().go(0);newTestThread().go(1);}}上面程序的运行结果为:i=1i=2i=3。
结果将一直打印出I的值。
我们的意图是当在while循环中调用sleep()时,另一个线程就将起动,打印出j的值,但结果却并不是这样。
深入理解JAVA多线程之线程间的通信方式
深⼊理解JAVA多线程之线程间的通信⽅式⼀,介绍本总结我对于JAVA多线程中线程之间的通信⽅式的理解,主要以代码结合⽂字的⽅式来讨论线程间的通信,故摘抄了书中的⼀些⽰例代码。
⼆,线程间的通信⽅式①同步这⾥讲的同步是指多个线程通过synchronized关键字这种⽅式来实现线程间的通信。
参考⽰例:public class MyObject {synchronized public void methodA() {//do something....}synchronized public void methodB() {//do some other thing}}public class ThreadA extends Thread {private MyObject object;//省略构造⽅法@Overridepublic void run() {super.run();object.methodA();}}public class ThreadB extends Thread {private MyObject object;//省略构造⽅法@Overridepublic void run() {super.run();object.methodB();}}public class Run {public static void main(String[] args) {MyObject object = new MyObject();//线程A与线程B 持有的是同⼀个对象:objectThreadA a = new ThreadA(object);ThreadB b = new ThreadB(object);a.start();b.start();}}由于线程A和线程B持有同⼀个MyObject类的对象object,尽管这两个线程需要调⽤不同的⽅法,但是它们是同步执⾏的,⽐如:线程B需要等待线程A执⾏完了methodA()⽅法之后,它才能执⾏methodB()⽅法。
Java线程间的通信方式
Java线程间的通信⽅式1. 同步,多个线程通过synchronized关键字实现线程间的通信。
(个⼈理解:使⽤synchronized和第3种⽅法使⽤wait/notify是同⼀种⽅式)例⼦:⼦线程循环3次,接着主线程循环5次,接着⼜回到⼦线程循环3次,接着在回到主线程循环5次,如此循环4次代码实现:public class SychronizedTest {public static void main(String[] args) {final Business business = new Business();new Thread(new Runnable() {@Overridepublic void run() {for (int j = 1; j <= 4; j++) {business.sub(j);}}}).start();for (int j = 1; j <= 4; j++) {business.main(j);}}}class Business {private boolean bshouldSub = true;// ⼦线程和主线程通信信号public synchronized void sub(int j) {if (!bshouldSub) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 1; i <= 3; i++) {System.out.println("sub sthread sequece of " + i + ",loop of " + j);}bshouldSub = false;// 运⾏结束,设置值为FALSE 让主程序运⾏this.notify();// 唤醒等待的程序}public synchronized void main(int j) {if (bshouldSub) {// 如果bshouldsub=true ,等待, 让⼦程序运⾏try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 1; i <= 5; i++) {System.out.println("main sthread sequece of " + i + ",loop of " + j);}bshouldSub = true;// 让⼦程序运⾏this.notify();// 唤醒等待的⼀个程序}}在business中,使⽤synchronized实现两个⽅法互斥。
Java线程间通信的几种方式
Java线程间通信的⼏种⽅式Java编程思想中有这样⼀句话:当我们使⽤线程来同时运⾏多个任务时,可以通过使⽤锁(互斥)来同步两个任务的⾏为,从⽽使得⼀个任务不会⼲扰到另外⼀个任务,这解决的是线程间彼此⼲涉的问题,现在我们需要来解决线程间彼此协调的问题,也就是线程间通信问题。
其实我⼀直对线程间通信这个概念⽐较模糊,如果仅仅从线程间相互协调来讲,只要不是单个线程孤⽴的独⾃执⾏,就都会涉及到线程间交互问题,都属于线程间通信的范畴。
join:⼀个线程会让另外⼀个线程加⼊进来执⾏完成,这⾥就涉及到协调。
⽣产者/消费者模型:是⽣产者与消费者间的协调,两者间通过阻塞队列联系起来。
线程⼯具类,如CountDownLatch,Semaphore等也涉及到线程协调。
更⼴义⼀点的,线程中断,在⼀个线程中发起对另外⼀个线程的中断请求,另外⼀个线程响应中断,也涉及到协调。
以下是《Java编程思想》中提到的⼏种线程间通信的⽅式。
wait/notify/notifyAllLock和Condition管道阻塞队列1.wait和notify/notifyAll可以借助于Object类提供的wait()、notify()、notifyAll()三个⽅法,这三个⽅法属于Object类。
但这三个⽅法必须由同步监视器对象来调⽤,这可分为两种情况①对于⽤synchronized修饰的同步⽅法,因为该类的默认实例(this)就是同步监视器,所以可以在同步⽅法中直接调⽤这三个⽅法。
②对于⽤synchronized修饰的同步代码块,同步监视器是synchronized后括号⾥的对象,所以必须使⽤该对象调⽤这三个⽅法。
需要注意的是notify()⽅法只能随机唤醒⼀个线程,如果要唤醒所有线程,请使⽤notifyAll()。
/*** 来源;《Java编程思想》P709* 程序功能:⼀个餐厅有厨师和服务员。
厨师准备好膳⾷后,通知服务员上菜,服务员上菜后等待。
多线程之间实现通讯
@Override public void run() {
int count = 0; while (true) {
synchronized (res) { if (count == 0) {
erName = "余胜军"; res.sex = "男"; } else { erName = "小红"; res.sex = "女"; } count = (count + 1) % 2; }
while (true) { System.out.println(erName + "--" + erSex);
} } }
运行代码
Res res = new Res(); IntThrad intThrad = new IntThrad(res); OutThread outThread = new OutThread(res); intThrad.start(); outThread.start();
} } }
class OutThrad extends Thread { private Res res;
public OutThrad(Res res) { this.res = res;
}
@Override public void run() {
while (true) { synchronized (res) { System.out.println(erName + "," + res.sex); }
}
} } }
输出线程加上 synchronized
class Res { public String userName; public String sex;
JAVA学习(线程间通信:共享内存,等待唤醒;)
JAVA学习(线程间通信:共享内存,等待唤醒;)⼀、线程间通信如果每个线程间都孤⽴的运⾏,那就会造资源浪费。
所以在现实中,我们需要这些线程间可以按照指定的规则共同完成⼀件任务,所以这些线程之间就需要互相协调,这个过程被称为线程的通信。
线程通信就是当多个线程共同操作共享的资源时,互相告知⾃⼰的状态以避免资源争夺。
线程间通讯的⽅式: (存在多种⽅式,这⾥只写了共享内存,等待唤醒)1.共享内存:使⽤这种⽅式进⾏线程通信,通常会设置⼀个共享变量。
然后多个线程去操作同⼀个共享变量。
从⽽达到线程通讯的⽬的。
同时在多个线程操作同⼀个资源的过程中,必须要考虑的是共享变量的同步问题,这也共享内存容易出错的原因所在。
在这种通讯模型中,不同的线程之间是没有直接联系的。
都是通过共享变量这个“中间⼈”来进⾏交互。
⽽这个“中间⼈”必要情况下还需被保护在临界区内(加锁或同步)。
由此可见,⼀旦共享变量变得多起来,并且涉及到多种不同线程对象的交互,这种管理会变得⾮常复杂,极容易出现死锁等问题。
例如:设置⼀个共享资源Resoure类,Input类⽤来输⼊信息,Output⽤来提取信息,ResourceDemo类⽤来调⽤执⾏,public class Resource {String name;String sex;}public class Input implements Runnable{Resource r;Input(Resource r){this.r = r;}public void run(){int x = 0;while(true)synchronized (r) { //Input与Output共⽤⼀个锁rif (x == 0) { = "⼩明";r.sex = "男";} else { = "⼩红";r.sex = "⼥";}}x = (x + 1) % 2;}}}public class Output implements Runnable{Resource r;Output(Resource r){this.r = r;}public void run(){while(true) {synchronized (r) {System.out.println( + "...." + r.sex);}}}}public class ResourceDemo {public static void main(String[] args) {Resource r = new Resource();Input in = new Input(r); //将对象r作为参数传递,Input,Output共⽤⼀个锁Output out = new Output(r);Thread t1 = new Thread(in);Thread t2 = new Thread(out);t1.start();t2.start();}}2.等待唤醒机制:涉及的⽅法:<1>wait(); 让线程处于冻结状态,被wait的线程会被存储到线程池中。
JAVA技巧(Java线程间的通信)
线程间的通信(⽣产者-消费者模式) 有如下情形,线程A向盘⼦⾥放桔⼦(盘⼦很⼩,只能容得下⼀个桔⼦),放完桔⼦后,如果其它线程没有来拿桔⼦,则A下次再放桔⼦时,留在盘⼦⾥的上次那个桔⼦就被覆盖掉了(现实并⾮这样),但我们并不希望这个可⼝的桔⼦就这样被第⼆个桔⼦覆盖掉。
我们的理想情况是:线程A每次在盘⼦⾥放完⼀个桔⼦后,马上通知其它线程来取这个桔⼦,这时,线程A就暂停放桔⼦在盘⼦⾥,其它线程取⾛桔⼦之后,马上通知A桔⼦已经被取⾛,这时,A继续放下⼀个桔⼦,并通知其它线程来取,这样反复下去(为了不让产⽣者永久的放,消费者永久地取,可限定⽣产者⼀共要放100次桔⼦)……于是,放⼀个就取⾛⼀个,所有桔⼦都被成功取⾛。
在上述案例⼦中,线程A与线程B之间是⽣产者与消费者的关系,线程A⽣产桔⼦,把桔⼦在盘⼦⾥,线程B从盘⼦⾥拿⾛桔⼦,享受美味。
⽽且,为了达到⽣产⼀个,拿⾛⼀个,这样的⼀对⼀的过程,线程A必须告诉线程B:桔⼦已经放好了,来拿吧,你拿⾛了,我再放下⼀个。
当线程B拿⾛后,必须告诉线程A:我把桔⼦拿⾛了,你快放下⼀个吧。
线程A和B互相告诉对⽅的动作,就是线程间的通信。
取放桔⼦的整个过程,涉及到了四个对象,分别是⽣产者(线程A),消费者(线程B),消费的商品(桔⼦),商店(盘⼦)。
因此,可以把上述过程看作是⽣产者和消费者在商店⾥交易桔⼦。
下图描绘了上述整个过程: 下⾯的代码实现了本案例: class MyTest1{ public static void main(String[] args){ Panel pan = new Panel(); Consumer c = new Consumer(pan); Producer p = new Producer(pan, c); c.setDaemon(true);/*将消费者设为守护线程,也就是说,当⽣产者不再⽣产时,消费者⽴即主动不再消费*/ p.start(); c.start(); } }class Producer extends Thread{ Panel pan = null; Consumer c = null; public Producer(Panel pan, Consumer c){ this.pan = pan; this.c = c; } public void run(){ synchronized(c){ int count = 0; //Examda提⽰: ⽣产者⼀共要⽣产100个桔⼦ while(count++ < 100){ if(!pan.isBlank){ try{c.wait();}catch(Exception ex){ex.printStackTrace();} } int orgWeight = (int)(Math.random() * 100); Orange org = new Orange(orgWeight, "red"); pan.putOrange(org); c.notify(); } } } } class Consumer extends Thread{ Panel pan; public Consumer(Panel pan){ this.pan = pan; } public void run(){ synchronized(this){ while(true){ if(pan.isBlank){ try{wait();}catch(Exception ex){ex.printStackTrace();} } pan.getOrange(); notify(); } } } } class Orange{ int weight; String color; public Orange(int weight, String color){ this.weight = weight; this.color = color; } public String toString(){ return "Orange, weight = " + weight + ", color = " + color; } } class Panel{ public boolean isBlank = true; private Orange org; public void putOrange(Orange org){ = org; isBlank = false; System.out.println("I put: " + org.toString()); } public Orange getOrange(){ System.out.println("I get: " + org.toString()); isBlank = true; return org; } }。
Java多线程通信方法
Java多线程通信方法
导语:多线程间通讯就是多个线程在*作同一资源,但是*作的动作不同,下面让我们了解一下吧!
多线程通信方法
(1)为什么要通信
多线程并发执行的时候,如果需要指定线程等待或者唤醒指定线程,那么就需要通信.比如生产者消费者的问题,
生产一个消费一个,生产的时候需要负责消费的进程等待,生产一个后完成后需要唤醒负责消费的线程,
同时让自己处于等待,消费的时候负责消费的线程被唤醒,消费完生产的产品后又将等待的生产线程唤醒,
然后使自己线程处于等待。
这样来回通信,以达到生产一个消费一个的目的。
(2)怎么通信
在同步代码块中,使用锁对象的wait()方法可以让当前线程等待,直到有其他线程唤醒为止.
使用锁对象的notify()方法可以唤醒一个等待的线程,或者notifyAll唤醒所有等待的线程.
多线程间通信用sleep很难实现,睡眠时间很难把握。
停止线程的方法:
stop方法已经过时,如何停止线程?
停止线程的方法只有一种,就是run方法结束。
如何让run方法结束呢?
开启多线程运行,运行代码通常是循环体,只要控制住循环,就可以让run方法结束,也就是结束线程。
特殊情况:当线程属于冻结状态,就不会读取循环控制标记,则线程就不会结束。
为解决该特殊情况,可引入Thread类中的Interrupt方法结束线程的冻结状态;
当没有指定的方式让冻结线程恢复到运行状态时,需要对冻结进行清除,强制让线程恢复到运行状态。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例 14: class TestThreadMethod extends Thread{ public static int shareVar = 0; public TestThreadMethod(String name){ super(name); } public synchronized void run(){ for(int i=0; i<4; i++){ System.out.print(Thread.currentThread().getName()); System.out.println(" : " + i); Thread.yield(); } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); TestThreadMethod t2 = new TestThreadMethod("t2"); t1.start(); t1.start(); //(1) //t2.start(); (2) } } 运行结果为: t1 : 0 t1 : 1 t1 : 2 t1 : 3 t1 : 0 t1 : 1 t1 : 2 t1 : 3 从结果可知调用 yield()时并不会释放对象的“锁标志”。 如果把代码(1)注释掉,并去掉代码(2)的注释,结果为: t1 : 0 t1 : 1 t2 : 0 t1 : 2 t2 : 1 t1 : 3 t2 : 2 t2 : 3 从结果可知,虽然 t1 线程调用了 yield(),但它马上又被执行了。 2.4 sleep()和 yield()的区别
彻底明白 Java 的多线程-线程间的通信
作者:未知
文章来源:
发布日期:2005 年 01 月 19 日
浏览次数:1711 次
三. 线程间的通信
1. 线程的几种状态
线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过 new 产生
System.out.println(" shareVar = " + shareVar);
this.resume(); //(2) } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); TestThreadMethod t2 = new TestThreadMethod("t2"); t1.start(); //(5) //t1.start(); //(3) t2.start(); //(4) } } 运行结果为: t2 shareVar = 5 i. 当代码(5)的 t1 所产生的线程运行到代码(1)处时,该线程进入停滞状态。然后 排程器从线程池中唤起代码(4)的 t2 所产生的线程,此时 shareVar 值不为 0,所以执 行 else 中的语句。 ii. 也许你会问,那执行代码(2)后为什么不会使 t1 进入可执行状态呢?正如前面所 说,t1 和 t2 是两个不同对象的线程,而代码(1)和(2)都只对当前对象进行操作, 所以 t1 所产生的线程执行代码(1)的结果是对象 t1 的当前线程进入停滞状态;而 t2 所产生的线程执行代码(2)的结果是把对象 t2 中的所有处于停滞状态的线程调回到可 执行状态。 iii. 那现在把代码(4)注释掉,并去掉代码(3)的注释,是不是就能使 t1 重新回到 可执行状态呢?运行结果是什么也不输出。为什么会这样呢?也许你会认为,当代码(5) 所产生的线程执行到代码(1)时,它进入停滞状态;而代码(3)所产生的线程和代码 (5)所产生的线程是属于同一个对象的,那么就当代码(3)所产生的线程执行到代码 (2)时,就可使代码(5)所产生的线程执行回到可执行状态。但是要清楚,suspend() 函数只是让当前线程进入停滞状态,但并不释放当前线程所获得的“锁标志”。所以当 代码(5)所产生的线程进入停滞状态时,代码(3)所产生的线程仍不能启动,因为当 前对象的“锁标志”仍被代码(5)所产生的线程占有。 2.2 sleep() 1) sleep ()函数有一个参数,通过参数可使线程在指定的时间内进入停滞状态,当指 定的时间过后,线程则自动进入可执行状态。 2) 当调用 sleep ()函数后,线程不会释放它的“锁标志”。 例 12: class TestThreadMethod extends Thread{ class TestThreadMethod extends Thread{ public static int shareVar = 0; public TestThreadMethod(String name){ super(name); } public synchronized void run(){ for(int i=0; i<3; i++){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
if(shareVar==5){
this.suspend(); //(1)
}
}
}
else{
System.out.print(Thread.currentThread().getName());
} public synchronized void run(){ for(int i=0; i<5; i++){ System.out.print(Thread.currentThread().getName()); System.out.println(" : " + i); try{ if(Thread.currentThread().getName().equals("t1")) Thread.sleep(200); else Thread.sleep(100); } catch(InterruptedException e){ System.out.println("Interrupted"); } } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); TestThreadMethod t2 = new TestThreadMethod("t2"); t1.start(); //t1.start(); t2.start(); } } 运行结果为: t1 : 0 t2 : 0 t2 : 1 t1 : 1 t2 : 2 t2 : 3 t1 : 2 t2 : 4 t1 : 3 t1 : 4 由于线程 t1 调用了 sleep(200),而线程 t2 调用了 sleep(100),所以线程 t2 处于停滞 状态的时间是线程 t1 的一半,从从结果反映出来的就是线程 t2 打印两倍次线程 t1 才 打印一次。 2.3 yield() 1) 通过 yield ()函数,可使线程进入可执行状态,排程器从可执行状态的线程中重新 进行排程。所以调用了 yield()的函数也有可能马上被执行。 2) 当调用 yield ()函数后,线程不会释放它的“锁标志”。
后,除非收到 resume()消息,否则该线程不会变回可执行状态。
2) 当调用 suspend()函数后,线程不会释放它的“锁标志”。
例 11:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
一个线程调用 wait()函数后,线程就进入停滞状态,只有当两次对该线程调用 notify
或 notifyAll 后它才能两次回到可执行状态。
2. cБайду номын сангаасass Thread 下的常用函数函数
2.1 suspend()、resume()
1) 通过 suspend()函数,可使线程进入停滞状态。通过 suspend()使线程进入停滞状态
System.out.print(Thread.currentThread().getName()); System.out.println(" : " + i); try{ Thread.sleep(100); //(4) } catch(InterruptedException e){ System.out.println("Interrupted"); } } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); TestThreadMethod t2 = new TestThreadMethod("t2"); t1.start(); (1) t1.start(); (2) //t2.start(); (3) } } 运行结果为: t1 : 0 t1 : 1 t1 : 2 t1 : 0 t1 : 1 t1 : 2 由结果可证明,虽然在 run()中执行了 sleep(),但是它不会释放对象的“锁标志”, 所以除非代码(1)的线程执行完 run()函数并释放对象的“锁标志”,否则代码(2)的 线程永远不会执行。 如果把代码(2)注释掉,并去掉代码(3)的注释,结果将变为: t1 : 0 t2 : 0 t1 : 1 t2 : 1 t1 : 2 t2 : 2 由于 t1 和 t2 是两个对象的线程,所以当线程 t1 通过 sleep()进入停滞时,排程器会从 线程池中调用其它的可执行线程,从而 t2 线程被启动。 例 13: class TestThreadMethod extends Thread{ public static int shareVar = 0; public TestThreadMethod(String name){ super(name);