Java 多线程间通信
JDK 1.5 以后, 将同步和锁封装成了对象, 并将操作锁的隐式方法定义到了该对象中, 将隐式动作变成了显示动作.
Lock 接口
- Lock 接口, 位于 java.util.concurrent.locks 包中, 使用该接口需要导包.
- Lock 接口的出现替代了同步代码块或者同步函数, 因为同步代码块对于锁的操作(获取或释放)是隐式的.
Lock 接口将同步的隐式锁操作变成显式锁操作. 同时,更为灵活, 可以在一个锁上加上多个监视器. - Lock 接口中的方法:
- lock(): 获取锁
- unlock(): 释放锁, 这个动作是必须要完成的, 所以通常需要定义在 finally 代码块中
- 格式:
Lock lock = new ReentrantLock(); // Lock 接口的实现类
void show()
{
try
{
lock.lock(); //获取锁
// 执行代码...
}
finally
{
lock.unlock(); // 释放锁
}
}
Condition 接口
- Condition 接口的出现替代了 Object 类中的 wait(), notify(), notifyAll()方法,将这些
监视器方法单独进行了封装, 变成 Condition 监视器对象, 可以与任意锁进行组合. - 常用方法:
- await(): 让线程处于冻结状态
- signal(): 唤醒一个等待线程
- signalAll(): 唤醒所有等待线程
- 格式:
Condition c1 = lock.newCondition(); // 新建一个监视器对象
JDK 升级以后的多生产者/多消费者
class Resource
{
private String name;
private int count = 1; // 记录烤鸭的编号
private boolean flag = false;
// 创建一个锁对象
Lock lock = new ReentrantLock();
// 通过已有的锁获取两组监视器, 一组监视生产者, 一组监视消费者
Condition producer_con = lock.newCondition();
Condition consumer_con = lock.newCondition();
public void set(String name)
{
lock.lock(); //获取锁
try
{
while(flag)
try{producer_con.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
flag = true;
consumer_con.signal();
}
finally
{
lock.unlock(); //释放锁
}
}
public void out()
{
lock.lock(); //获取锁
try
{
while(!flag)
try{consumer_con.wait();}catch(InterruptedException e){}
Sytem.out.println(Thread.currentThread().getName()+ "...消费者.."+ this.name);
flag = false;
producer_con.signal();
}
finally
{
lock.unlock(); //释放锁
}
}
}
class Producer implements Runnable
{
Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
class ProducerConsumerDemo
{
public static void main(String[] args)
{
// 创建资源
Resource r = new Resource();
// 创建任务
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
// 多生产者
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
// 多消费者
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
Thread t5 = new Thread(con);
// 开启线程
t0.start();
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
wait() 和 sleep() 的区别
- wait() 可以指定时间也可以不指定时间
sleep() 必须指定时间. - 在同步中, 对 CPU 的执行权和锁的处理不同
- wait(): 释放执行权, 释放锁
- sleep(): 释放执行权, 不释放锁
停止线程
- run() 方法结束
- 怎么控制线程的任务结束呢?
- 任务中都会有循环结构, 只要控制住循环就可以结束任务.
- 控制循环通常就用定义标记(条件)来完成.
class StopThread implements Runnable
{
// 定义标记
private boolean flag = true;
public void run()
{
while(flag)
{
System.out.println(Thread.currentThread().getName()+".....");
}
}
// 对外提供改变标记的方法
public void setFlag()
{
flag = false;
}
}
class StopThreadDemo
{
public static void main(String[] args)
{
StopThread st = new StopThread();
Thread t0 = new Thread(st);
Thread t1 = new Thread(st);
t1.start();
t2.start();
int num = 1;
for(;;)
{
if(++num==50)
{
st.setFlag(); // 更改标记
break;
}
System.out.println("main....."+num);
}
System.out.println("over");
}
}
- 如果线程处于冻结状态, 无法读取标记, 如何结束呢?
- 可以使用 interrupt() 方法将线程从冻结状态强制恢复到运行状态, 让线程具备 CPU 的执行资格.
- 该强制动作会发生 InterruptedException, 需要处理.
class StopThread implements Runnable
{
// 定义标记
private boolean flag = true;
public synchronized void run() //此处将函数变为同步函数
{
while(flag)
{
try
{
wait();//t0, t1 线程执行到这句时, 都会被处于冻结状态
}
catch(InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+"..."+e);
flag = false; // 更改标记
}
System.out.println(Thread.currentThread().getName()+".....");
}
}
// 对外提供改变标记的方法
public void setFlag()
{
flag = false;
}
}
class StopThreadDemo
{
public static void main(String[] args)
{
StopThread st = new StopThread();
Thread t0 = new Thread(st);
Thread t1 = new Thread(st);
t0.start();
t1.start();
int num = 1;
for(;;)
{
if(++num==50)
{
t0.interrupt(); // 清除中断状态
t1.interrupt(); // 清除中断状态
break;
}
System.out.println("main....."+num);
}
System.out.println("over");
}
}
线程类的其他方法
- setDaemon(boolean b) : 将该线程标记为守护线程(后台线程).
- join() : 临时加入一个线程运算时, 可以使用 join() 方法, 需要处理 InterruptedException
class Demo implements Runnable
{
public void run()
{
for(int x=0; x<50; x++)
{
System.out.println(Thread.currentThread().getName()+"......"+x);
}
}
}
class JoinDemo
{
public static void main(String[] args) throws Exception
{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t1.join(); // 临时加入 t1 线程, 执行权移交给 t1, 必须等 t1 运行完成后, 其他线程才运行
t2.start();
for(int x=0; x<50; x++)
{
System.out.println(Thread.currentThread().getName()+"..."+x);
}
}
}
- toString() : 返回该线程的字符串表示形式, 包括线程名称, 优先级和线程组.
- 优先级: 获取 CPU 执行权的机率, 分为 1~10个数字, 其中:
- 最高优先级: MAX_PRIORITY , 代表数值 10
- 最低优先级: MIN_PRIORITY , 代表数值 1
- 默认优先级: NORM_PRIORITY , 代表数值 5
- yield(): 暂停当前正在执行的线程对象, 并执行其他线程.
- JavaSE 基础视频(毕向东)
- Java中的ReentrantLock和synchronized两种锁定机制的对比
- Java 并发:线程间通信与协作
- JAVA线程间通信的几种方式(打印1A2B....)
Java 多线程间通信的更多相关文章
- java 多线程间通信(二)
传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...
- Java多线程间通信-解决安全问题、等待唤醒机制
/*1.增加一个知识点一个类怎么在所有的类中,让其它类来共同修改它的数据呢?可以用单例设计模式可以用静态可以在其它类中做一个构造函数,接受同一个对象,这样就可以实现对象 2.状态选择可以用数字0 1 ...
- java 多线程间通信(一)
synchronized同步 package com.test7; public class Run { public class MyObject { private int a; public M ...
- Java线程间通信-回调的实现方式
Java线程间通信-回调的实现方式 Java线程间通信是非常复杂的问题的.线程间通信问题本质上是如何将与线程相关的变量或者对象传递给别的线程,从而实现交互. 比如举一个简单例子,有一个多线程的 ...
- (十一)boost库之多线程间通信
(十一)boost库之多线程间通信 1.互斥锁 在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性.每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一 ...
- Java 多线程间的通讯
在前一小节,介绍了在多线程编程中使用同步机制的重要性,并学会了如何实现同步的方法来正确地访问共享资源.这些线程之间的关系是平等的,彼此之间并不存在任何依赖,它们各自竞争CPU资源,互不相让,并且还无条 ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
- 说说Java线程间通信
序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在 ...
- 说说 Java 线程间通信
序言 正文 一.Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在一个 ...
随机推荐
- 算法模板学习专栏之总览(会慢慢陆续更新ing)
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/7495310.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- ACM-ICPC 2017 Asia Urumqi:A. Coins(DP)
挺不错的概率DP,看似基础,实则很考验扎实的功底 这题很明显是个DP,为什么???找规律或者算组合数这种概率,N不可能给的这么友善... 因为DP一般都要在支持N^2操作嘛. 稍微理解一下,这DP[i ...
- 百度之星-day2-1004-二分答案
由于序列有序,求其中一个最优解,二分答案即可,注意二分时上边界满足才保存 #include<iostream> #include<stdio.h> #include<st ...
- C. Rectangles
链接 [http://codeforces.com/group/1EzrFFyOc0/contest/1028/problem/C] 题意 给你n个矩形的左下角和右上角坐标,问你至少包含在n-1个矩形 ...
- 个人博客-week7
团队任务收获及个人感想 团队任务已经进行了一个多月的时间,我很荣幸能和软剑攻城队的小伙伴们度过这一个月的开发时光.在这一个月的时间里,我亲身经历了一个软件从想法到实现,从创意到实体的过程.同时我也在和 ...
- Linux内核分析作业第四周
系统调用的三个层次 一.用户态.内核态和中断 用户通过库函数与系统调用联系起来. 1.内核态 在高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态 2.用户态: 在低级 ...
- centos7编译安装zabbix(附带编译安装lnmp)
先把防火墙和selinux关闭: sytemctl stop firewalld setenforce 0 1.yum安装依赖: yum -y install wget openssl* gcc gc ...
- Windows命令行下如何使用批处理异步打开一个浏览器进程
Browse.bat @echo off if '%1'=='-c' ( start /d "C:\Program Files\Google\Chrome\Application\" ...
- C++ cout执行顺序
C++ cout执行顺序 问题描述是这样的:如果在cout中调用函数,同时这个函数中包含输出语句,那么会先输出哪一句? 仔细一看,突然发现对C++的内容遗忘了,确实一下子看不出来输出的先后问题. 实现 ...
- WMS与MES集成
ERP的物流管理只偏重于帐务的管理,对现场实物流的及时性和精细程度管理均不够,无法满足企业日益精细化管理的需求,WMS可以弥补这个缺陷,WMS采用条码技术及时反应物流过程中的变化,同时将存量细化到货架 ...