线程与线程,进程与进程之间的通信

线程与线程,进程与进程之间的通信
线程与线程之间的通信
⼀,为什么要线程通信?
1>多个线程并发执⾏时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成⼀件任务, 并且我们希望他们有规律的执⾏, 那么多线程之间需要⼀些协调通信,以此来帮我们达到多线程共同操作⼀份数据。
2>当然如果我们没有使⽤线程通信来进⾏多线程共同操作同⼀份数据的话,虽然可以实现,但是在很⼤程度会造成多线程之间对同⼀共享变量的争夺,那样的话势必为造成很多错误和损失!
3>所以,我们才引出了线程之间的通信,多线程之间的通信能够避免对同⼀共享变量的争夺。
⼆,什么是线程通信?
  多个线程在处理同⼀个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同⼀个变量的使⽤或操作。就是多个线程在操作同⼀份数据时, 避免对同⼀共享变量的争夺。
三,线程之间通信⽅式:
1.是通过共享变量,线程之间通过该变量进⾏协作通信;
2.通过队列(本质上也是线程间共享同⼀块内存)来实现消费者和⽣产者的模式来进⾏通信;
1.于是我们引出了等待唤醒机制:(wait()、notify())就是在⼀个线程进⾏了规定操作后,就进⼊等待状态(wait), 等待其他线程执⾏完他们的指定代码过后 再将其唤醒(notify);
线程等待与唤醒的概述
线程的等待与唤醒⼜称为线程之间的通信,等待与唤醒机制是实现两个或多个线程在执⾏任务过程相互配合相互协作的⼀种技术。
void  wait():等待,让出cpu进⼊等待状态(如果⼀个线程内调⽤了该⽅法,那么该线程就停⽌运⾏,等待其他线程唤醒,或者其他线程调⽤notifAll⽅法)
线程调⽤wait()⽅法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的⽅式是notify()或者notifyAll()⽅法),这样它才能重新获得锁的拥有权和恢复执⾏。
要确保调⽤wait()⽅法的时候拥有锁,即,wait()⽅法的调⽤必须放在synchronized⽅法或synchronized块中。
void  notify():唤醒,随机唤醒⼀个正在等待的线程,让其进⼊可运⾏状态(解除了调⽤wait⽅法线程的等待状态,让其变成可运⾏状态)
void  notifyAll():唤醒所以进⼊等待状态的线程,让其都进⼊可运⾏状态
以上⽅法都定义在类:Object中
因为,这些⽅法在操作同步中的线程的时候,都必须标⽰其所操作线程所持有的锁(被该锁的对象调⽤),⽽只有同⼀个对象监视器下(同⼀个锁上)的被等待线程,可以被持有该锁的线程唤醒,(⽆法唤醒不同锁上的线程)所以,等待和唤醒的必须是同⼀个对象的监视器①下(同⼀个锁上)的线程。
⽽锁可以是任意已近确定的对象, 能 被任意对象调⽤的⽅法应当定义在 Object类中。
监视器(锁):同⼀个对象的监视器下(同⼀个锁上)的线程,⼀次只能执⾏⼀个:就是拥有监视器所有权(持有锁)的那⼀个线程。
注意事项:  使⽤wait,notify,notifyAll⽅法必须是锁对象调⽤,必须在同步代码块,或者是同步⽅法和cock和unlcok⽅法中间调⽤。awaitNotify;
import java. urrent.ExecutorService;
import urrent.Executors;
import urrent.TimeUnit;
/**
* 通过共享⼀个变量,wait()+notify() 来践⾏通信
* wait()和notify()⽅法要求在调⽤时线程已经获得了对象的锁,因此对这两个⽅法的调⽤需要放在synchronized⽅法或synchronized块中。*
* 针对两个线程的时候  没有问题
* 针对线程⼀多的时候, 就必须要⽤notifyAll()
* @author leo-zeng
*  */
public class NumberHolder {
private int number;
public synchronized void increase(){
while(number !=0){
try {
//若是nuber 不为0 时 等待
wait();
} catch (InterruptedException e) {
e.printStackTrace();
水烟炭
}
}
//能执⾏到这⾥,说明 已经被唤醒了,并且为0
number ++;
System.out.println("我要递增:"+number);
//通知在等待的线程
notifyAll();
}
public synchronized void decrease(){
//这⾥⽤while 不⽤ if 是因为保证可能多线程中,杜绝可能累加/递减会进⾏多次的可能。        while(number ==0){立云购物商城
try {
//若是等于零的时候  等待唤醒
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//能执⾏到这⾥,说明 已经被唤醒了,并且不为0
number --;
System.out.println("我要递减:"+number);
notifyAll();
}
public static void main(String[] args) {
ExecutorService pool = wFixedThreadPool(10);
NumberHolder holder  =new NumberHolder();
//执⾏任务
pool.shutdown();
try {
pool.awaitTermination(300,TimeUnit.SECONDS);
} catch (InterruptedException e) {
连供系统
e.printStackTrace();
}
}
}
/**
* 累加的类
* @author leo
*  */
class IncreaseThread extends Thread{
private NumberHolder numberHolder;
public IncreaseThread(NumberHolder numberHolder) {        this.numberHolder =numberHolder;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//每次都有不多的延迟
try {
Thread.sleep((long)Math.random()*1000);
} catch (InterruptedException e) {
e.printStackTrace();
电动窗帘配件}
//执⾏新增操作
numberHolder.increase();
}
}
钢板切割}
class DecreaseThread extends Thread{
private NumberHolder holder;
public DecreaseThread(NumberHolder holder){
this.holder =holder;
}
@Override
public void run() {
摄像机广角镜头for (int i = 0; i <20; i++) {
//每次都有不多的延迟
try {
Thread.sleep((long)Math.random()*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//执⾏递减函数
holder.decrease();
}
}
}
2.通过队列来实现线程的通信
这⾥⽤的是urrent包中linkedBlockingQueue 来进⾏线程间交互;
urrent.LinkedBlockingQueue 是⼀个基于单向链表的、范围任意的(其实是有界的)、FIFO 阻塞队列。访问与移除操作是在队头进⾏,添加操作是在队尾进⾏,并分别使⽤不同的锁进⾏保护,只有在可能涉及多个节点的操作才同时对两个锁进⾏加锁。
这⾥通过共享⼀个队列的信息,实现⽣产者和消费者
awaitNotify;
import urrent.ExecutorService;
import urrent.Executors;
import urrent.LinkedBlockingQueue;
import urrent.TimeUnit;
/**
* 通过linkedblockingQueue 构建线程间通信
* @author leo-zeng
*

本文发布于:2024-09-23 12:27:08,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/101653.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   等待   唤醒
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议