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;
//省略构造方法
@Override
public void run() {
super.run();
object.methodA();
}
}

public class ThreadB extends Thread {

private MyObject object;
//省略构造方法
@Override
public void run() {
super.run();
object.methodB();
}
}

public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();

//线程A与线程B 持有的是同一个对象:object
ThreadA a = new ThreadA(object);
ThreadB b = new ThreadB(object);
a.start();
b.start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了通信。

这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。

while轮询

其实就是多线程同时执行,会牺牲部分CPU性能。

在这种方式下,线程A不断地改变条件,线程ThreadB不停地通过while语句检测这个条件(list.size()==5)是否成立 ,从而实现了线程间的通信。但是这种方式会浪费CPU资源。之所以说它浪费资源,是因为JVM调度器将CPU交给线程B执行时,它没做啥“有用”的工作,只是在不断地测试 某个条件是否成立。就类似于现实生活中,某个人一直看着手机屏幕是否有电话来了,而不是: 在干别的事情,当有电话来时,响铃通知TA电话来了。

import java.util.ArrayList;
import java.util.List;

public class MyList {

private List<String> list = new ArrayList<String>();
public void add() {
list.add("elements");
}
public int size() {
return list.size();
}
}

import mylist.MyList;

public class ThreadA extends Thread {

private MyList list;

public ThreadA(MyList list) {
super();
this.list = list;
}

@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
list.add();
System.out.println("添加了" + (i + 1) + "个元素");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

import mylist.MyList;

public class ThreadB extends Thread {

private MyList list;

public ThreadB(MyList list) {
super();
this.list = list;
}

@Override
public void run() {
try {
while (true) {
if (list.size() == 5) {
System.out.println("==5, 线程b准备退出了");
throw new InterruptedException();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

import mylist.MyList;
import extthread.ThreadA;
import extthread.ThreadB;

public class Test {

public static void main(String[] args) {
MyList service = new MyList();

ThreadA a = new ThreadA(service);
a.setName("A");
a.start();

ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
wait/notify机制
public class MyList {
private static List<String> list = new ArrayList<String>();

public static void add() {
list.add("anyString");
}

public static int size() {
return list.size();
}
}

public class ThreadA extends Thread {

private Object lock;

public ThreadA(Object lock) {
super();
this.lock = lock;
}

@Override
public void run() {
try {
synchronized (lock) {
if (MyList.size() != 5) {
System.out.println("wait begin " + System.currentTimeMillis());
lock.wait();
System.out.println("Interruption!!!");
//lock.wait();
lock.notify();
lock.wait();
System.out.println("wait end " + System.currentTimeMillis());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class ThreadB extends Thread {

private Object lock;

public ThreadB(Object lock) {
super();
this.lock = lock;
}

@Override
public void run() {
try {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
MyList.add();
if (MyList.size() == 5) {
lock.notify();
System.out.println("已经发出了通知");
lock.wait();
}
System.out.println("添加了" + (i + 1) + "个元素!");
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class Test {
public static void main(String[] args) {
try {
Object lock = new Object();

ThreadA a = new ThreadA(lock);
a.start();

Thread.sleep(50);

ThreadB b = new ThreadB(lock);
b.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
wait begin 1498007974397
添加了1个元素!
添加了2个元素!
添加了3个元素!
添加了4个元素!
已经发出了通知
Interruption!!!
添加了5个元素!
添加了6个元素!
添加了7个元素!
添加了8个元素!
添加了9个元素!
添加了10个元素!
1
2
3
4
5
6
7
8
9
10
11
12
13
线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list 的size。

A,B之间如何通信的呢?也就是说,线程A如何知道 list.size() 已经为5了呢?

这里用到了Object类的 wait() 和 notify() 方法。

当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。—不像②while轮询那样占用CPU

当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。

这种方式的一个好处就是CPU的利用率提高了。

管道通信
管道流主要用来实现两个线程之间的二进制数据的传播,下面以PipedInputStream类和PipedOutputStream类为例,实现生产者-消费者:

package test.pipe;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/**
* 我们以数字替代产品 生产者每5秒提供5个产品,放入管道
*/
class MyProducer extends Thread {

private PipedOutputStream outputStream;

private int index = 0;

public MyProducer(PipedOutputStream outputStream) {
this.outputStream = outputStream;
}

@Override
public void run() {
while (true) {
try {
for (int i = 0; i < 5; i++) {
outputStream.write(index++);
}
} catch (IOException e) {
e.printStackTrace();
}

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

/**
* 消费者每0.5秒从管道中取1件产品,并打印剩余产品数量,并打印产品信息(以数字替代)
*/
class MyConsumer extends Thread {

private PipedInputStream inputStream;

public MyConsumer(PipedInputStream inputStream) {
this.inputStream = inputStream;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
int count = inputStream.available();
if (count > 0) {
System.out.println("rest product count: " + count);
System.out.println("get product: " + inputStream.read());
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}

public class PipeTest1 {

public static void main(String[] args) {

PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
try {
pis.connect(pos);
} catch (IOException e) {
e.printStackTrace();
}

new MyProducer(pos).start();
new MyConsumer(pis).start();

}
}
---------------------
作者:Hadwin1991
来源:CSDN
原文:https://blog.csdn.net/Hadwin1991/article/details/73527835
版权声明:本文为博主原创文章,转载请附上博文链接!

转载于:https://www.cnblogs.com/lgyxrk/p/10404846.html

java实现线程间通信的四种方式相关推荐

  1. android 多线程间通信,android实现线程间通信的四种常见方式

    1,通过Handler机制 主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,需要传递conten ...

  2. JAVA线程间通信的几种方式

    今天在群里面看到一个很有意思的面试题: "编写两个线程,一个线程打印1~25,另一个线程打印字母A~Z,打印顺序为12A34B56C--5152Z,要求使用线程间的通信." 这是一 ...

  3. 线程间通信的几种方式

    Java线程间通信: 1:线程上下文 2:共享内存 3:IPC通信 4:套接字(Socket),不同的机器之间进行通信 另外:附注通信内容: linux常用的进程间的通讯方式 (1).管道(pipe) ...

  4. python 线程通信的几种方式_进程间通信和线程间通信的几种方式

    进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在当代 ...

  5. 进程间通信和线程间通信的几种方式

    进程和线程的区别: 对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品. 而线程,相对于进程而言,是一个更加接近于执行体的概念,可以和同进程的其他线程之间直接共享数 ...

  6. java 线程间通信的几种方式

    1.如何让两个线程依次执行 假设有两个线程,一个线程A,一个线程B,两个线程分别依次打印 1-3 三个数字即可. package Test;/** /*** @author Administrator ...

  7. android线程间通信的四种实现方式

    1,通过Handler机制. private void one() {handler=new Handler(){@Overridepublic void handleMessage(Message ...

  8. 线程间通信的两种方式

    1.wait()/notify() Object类中相关的方法有notify和wait方法,又因为它俩被定义在Object类中,故会被所有的类继承.它俩都是final的,不能被重写,不能通过子类重写改 ...

  9. Java 如何线程间通信,面试被问哭。。。

    Java 如何线程间通信,曾经小编面试被问哭的一道题.. 正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及 ...

最新文章

  1. OpenGL与CUDA互操作方式总结
  2. c# 获取machineguid_C#中怎么生成和获取GUID
  3. google us web
  4. 【终于等到你】7种策略解除云风险警报
  5. vmware配置centos全套
  6. 红外解码软件 android,一文教会你红外线遥控器软件解码程序
  7. 案例29-购物车提交订单
  8. 由项目浅谈JS中MVVM模式
  9. 怎样在photoshop中快速批量,修改图片
  10. 匹配 边覆盖 独立集 顶点覆盖
  11. HTML5-坦克大战一画出敌人坦克并让自己的坦克可以发子弹的功能(二)
  12. C_北理工乐学_结构
  13. GD32F303串口ISP方式下载程序
  14. mysql提示表不存在的解决方法error: 1146: Table doesn‘t exist
  15. 不知道CAD坐标系,如何做到CAD与卫星影像无偏叠加?
  16. Vmware 虚拟机克隆后网卡地址的修改
  17. 嵌入式系统测试教学实训平台系统情况
  18. java-php-python-ssm演唱会购票系统计算机毕业设计
  19. Python环境与PyCharm编辑器的安装教程
  20. Stata:gen命令中的group()函数的潜在风险

热门文章

  1. Python(五)列表
  2. Windows 8.1 重复数据删除
  3. maven学习十之myEclipse搭建maven项目总结
  4. selenium中webdriver跳转新页面后定位置新页面的两种方式
  5. 试水区块链出版?纽约时报在招人了
  6. WINKEY功能键你会用吗??
  7. 简单工厂模式--加减乘除运算
  8. dede织梦调用顶级二级栏目及下三级栏目方法(数据库实现)
  9. 我的Android进阶之旅------Android Studio 快捷键整理分享
  10. JPA扩展(自定义sql)