并发编程,一般指多线程编程,它可以充分利用计算机的计算资源,使得一个任务可以分为几个子模块同时执行,提高程序执行速度。然而,并不是启动越多线程,就能让程序执行越快,多线程同时带来了上下文切换、多线程间的通信与同步、死锁等问题。合理的利用多线程进行编程是一件有挑战性的事。

Java 自一开始就内置了对多线程的支持,在 JDK1.5 版本中引入了 java.util.concurrent 包,让 Java 的并发编程有了更多的选择和更好的工作方式。


多线程带来的问题

看下面一个例子,猜一下它的输出结果:

public class MultiThread {static int i = 0;public static int get() {return i++;}public static void main(String[] args) {for (int t = 0; t < 10; t++) {new Thread() {public void run() {System.out.println(get());}}.start();}}
}

输出结果:

1
0
2
3
4
5
6
7
8
9

注意,输出结果是不确定的,虽然大部分输出情况都是0-9顺序输出,但总会出现“异常情况”,也就是发生了冲突,当线程越多冲突的机会就越大。

输出结果不确定的原因在于程序中开了10个线程,而这10个线程是同步执行的,可能第二个线程比第一个线程先进行输出,也就出现了上面的结果。至于为什么大部分情况都是按顺序输出,因为虽然这10个线程是同步执行的,但是它们的启动顺序不一样,第一个线程最先启动,最后一个线程最后启动。


让线程按顺序输出

如果现在有10个线程,编号为0-9,我们想让0号线程执行完再执行1号线程,以此类推,最后执行9号线程。解决的方法是使用线程的 join() 方法。

假设线程的名字叫做 t,t.join() 方法的作用是将当前线程加入 t 线程,当 t 线程执行完后再执行当前线程。

示例如下:

public class JoinDemo {public static void main(String[] args) {Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(String.valueOf(i)) {public void run() {String name = Thread.currentThread().getName();int number = Integer.parseInt(name);if (number > 0)try {threads[number - 1].join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程名:" + name);}};threads[i].start();}}
}

输出结果:

线程名:0
线程名:1
线程名:2
线程名:3
线程名:4
线程名:5
线程名:6
线程名:7
线程名:8
线程名:9

程序中我们让后一个线程加到前一个线程中,使得只有前一个线程执行完了才能执行后一个线程。

t.join() 方法内部实际上是调用了 Object的wait() 方法,因此使用 join() 方法之前,需要先获得当前对象的锁,执行 wait() 方法后会释放当前对象的锁。


等待通知机制

等待/通知机制,是指一个线程A调用了对象 O 的 wait() 方法进入等待状态,另一个线程B调用了对象 O 的 notify() 或 notifyAll() 方法通知在对象上等待的线程,使其从 wait() 状态返回。两个线程间通过对象 O 来交互。

notify() 与 notifyAll() 的区别在于前者只会通知一个在对象上等待的线程,如果在该对象上等待的线程有多个,则会随机选取一个;后者会通知所有等待在该对象中的线程。

注意,对于 notifyAll() 来说,虽然所有的线程都被通知了。但是这些线程会进行竞争,且只会有一个线程成功获取到锁,在这个线程执行完毕之前,其他的线程必须等待。但 notifyAll() 免去了线程运行完后再通知其他线程的必要,因为之前已经通知过了所有的线程。

示例如下:

public class WaitNotify {static Object lock = new Object();static class Wait implements Runnable {public void run() {synchronized (lock) {System.out.println("线程" + Thread.currentThread().getName() + "开始等待");try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("继续执行时间:" + LocalTime.now().withNano(0));}}}static class Notify implements Runnable {public void run() {synchronized (lock) {System.out.println("线程" + Thread.currentThread().getName() + "开始通知");lock.notify();System.out.println("通知时间:" + LocalTime.now().withNano(0));}}}public static void main(String[] args) {Thread wait = new Thread(new Wait(), "wait");Thread notify = new Thread(new Notify(), "notify");wait.start();notify.start();}
}

输出结果:

线程wait开始等待
线程notify开始通知
通知时间:12:20:45
继续执行时间:12:20:45

注意,执行 notify() 或 notifyAll() 方法时不会释放 lock 的锁,直到 notify 线程释放了 lock 后,wait 线程才能从 wait() 方法中返回。

Java 多线程通信相关推荐

  1. java程序假死_分析一个常见的java多线程通信问题(假死现象)

    一件复杂的事,一个人如果不能做,两个人又做的不好,一群人就可能很好的解决了.对于线程来说也是,通过多个线程就能完成一个更复杂的功能,这就需要多个线程协作,协作就需要交流,但是交流总是会出问题的.在这篇 ...

  2. java多线程通信_Java多线程-线程通信

    原标题:Java多线程-线程通信 通信的方式 要想实现多个线程之间的协同,如:线程执行先后顺序.获取某个线程执行的结果等等.涉及到线程之间的相互通信,分为下面四类: 文件共享 网络共享 共享变量 JD ...

  3. Java 多线程 通信 通道 (猫狗赛跑)

    package thread; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOut ...

  4. java线程两个汽车赛跑,Java 多线程 通信 通道 (猫狗赛跑)

    package thread; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOut ...

  5. java多线程通信方法

    http://my.oschina.net/u/248570/blog/53226 转载于:https://www.cnblogs.com/svennee/p/4081153.html

  6. Java多线程通信-CyclicBarrier(栅栏)

    一.CyclicBarrier(栅栏) 通过闭锁,我们可以启动一组相关的操作.或者等待一组相关的操作结束.闭锁是一次性对象,到达终止状态后将不可用.     CyclicBarrier与闭锁类似,能够 ...

  7. Java多线程通信Suspend和Resume,为什么被弃用,如何导致死锁

    文章目录 Suspend和Resume作用 Suspend和Resume为什么被弃用 Suspend和Resume作用 suspend: 让线程挂起,暂停,程序停止往下执行. resume: 唤醒被s ...

  8. java多线程三之线程协作与通信实例

    多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...

  9. Java 多线程(七) 线程间的通信

    Java 多线程(七) 线程间的通信--wait及notify方法 线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法 ...

最新文章

  1. c语言子程序return,c语言return返回到哪
  2. pbs分解_UML使用产品分解结构(PBS)教程
  3. java hashmap 缓存
  4. 带防夹功能的升降器原理_全系标配行车自动落锁功能,全新凯美瑞表现分析
  5. SQL Server 大数据搬迁之文件组备份还原实战
  6. linux 继续编译,【编译】Linux环境编译traceroute
  7. 这是我见过最好的Flash知识介绍了!
  8. maven仓库启用国内云的方法,含完整配置文件
  9. mysql判断存在返回布尔_MySqlClient访问tinyint字段返回布尔值篇
  10. 又开火了!马斯克炮轰贝佐斯:建议分拆亚马逊!
  11. Node.js基础入门第七天
  12. 存储,对比私有云和公有云的不同
  13. html中易混淆的offset、client、scroll
  14. HW红队攻防基础建设—C2 IP隐匿技术
  15. java写满天繁星,描写满天繁星唯美句子
  16. Redis容量预估工具
  17. C语言教程(三):基础知识(续)
  18. c程序语言中long,C语言long
  19. python购物车结算不了_python中购物车
  20. 用python画竹子_智慧职教moocPython程序设计基础期末考试查题公众号答案

热门文章

  1. MaxPooling的作用
  2. 通俗的解释什么是Docker,一文搞懂
  3. 做Nodejs项目服务器部署
  4. 安卓模拟器安装APP,提示“this probably means that the app contains ARM native code and your Genymotion device ”
  5. win2012虚拟服务器,Win server2012如何创建虚拟机存储虚拟磁盘
  6. 【点灯鼠教程】K210裸机点灯之旅(1)点亮SSD1306【C开发I2C】
  7. 栈的初始化,入栈,出栈,遍历操作(代码实现) [数据结构][Java]
  8. 计算机提示没有有效的ip配置,电脑显示“本地连接没有有效的ip配置”怎么解决...
  9. 共享单车有了,可是路呢?
  10. AlertDialog自定义界面圆角显示