大家好,欢迎来到IT知识分享网。
一.为什么需要线程通讯
线程是操作系统调度的最小单位,有自己的栈空间,可以按照既定的代码逐步的执行,但是如果每个线程间都孤立的运行,那就会造资源浪费。所以在现实中,我们需要这些线程间可以按照指定的规则共同完成一件任务,所以这些线程之间就需要互相协调,这个过程被称为线程的通信。
线程间的通讯定义:多个线程在操作同一份数据时,互相告知自己的状态,避免对同一共享变量的争夺。
二.线程间的通讯方式
线程通讯的方式主要可以分为三种方式,共享内存、消息传递和管道流。
1.共享内存
(1)同步–synchronized
线程同步是线程之间按照⼀定的顺序执⾏,可以使⽤锁来实现达到线程同步,也就是在需要同步的代码块里加上关键字synchronized 。因为⼀个锁同⼀时间只能被⼀个线程持有。
synchronized可以修饰方法或者以同步块,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。
-
public
class
SynchronizedTest {
-
static
Object
obj
=
new
Object();
-
static
class
ThreadA
implements
Runnable{
-
-
@Override
-
public
void
run
() {
-
synchronized (obj){
-
for (
int
i
=
0; i <
5; i++) {
-
System.out.println(
"ThreadA" + i);
-
}
-
-
}
-
}
-
}
-
static
class
ThreadB
implements
Runnable{
-
-
@Override
-
public
void
run
() {
-
synchronized (obj){
-
for (
int
i
=
0; i <
5; i++) {
-
System.out.println(
"ThreadB" + i);
-
}
-
-
}
-
}
-
}
-
-
public
static
void
main
(String[] args) {
-
Thread
threada
=
new
Thread(
new
ThreadA());
-
Thread
threadb
=
new
Thread(
new
ThreadB());
-
threada.start();
-
threadb.start();
-
}
-
}
运行结果

线程A和线程B需要访问同一个对象lock,谁获得锁,谁就先执行。线程B要等线程A执行完再执行,所以是同步的,这就实现了线程间的通信
(2)信号量 –volatile
- 线程A把本地内存A更新过的共享变量刷新到主内存中
- 线程B到内存中去读取线程A之前已更新过的共享变量。
为保证线程间的通信必须经过主内存。需要关键字volatile。
volatile保证内存可见性,即多个线程访问内存中的同一个被volatile关键字修饰的变量时,当某一个线程修改完该变量后,需要先将这个最新修改的值写回到主内存,从而保证下一个读取该变量的线程取得的就是主内存中该数据的最新值,这样就保证线程之间的透明性,便于线程通信。
-
public
class
VolatileTest {
-
static
volatile
int
s
=
0;
-
static
class
ThreadA
implements
Runnable {
-
@Override
-
public
void
run
() {
-
while (s <
10) {
-
if (s %
2 ==
0) {
-
System.out.println(
"ThreadA: " + s);
-
synchronized (
this) {
-
s++;
-
}
-
}
-
}
-
}
-
}
-
static
class
ThreadB
implements
Runnable {
-
@Override
-
public
void
run
() {
-
while (s <
10) {
-
if (s %
2 ==
1) {
-
System.out.println(
"ThreadB: " + s);
-
synchronized (
this) {
-
s++;
-
}
-
}
-
}
-
}
-
}
-
public
static
void
main
(String[] args) {
-
Thread
threada
=
new
Thread(
new
ThreadA());
-
Thread
threadb
=
new
Thread(
new
ThreadB());
-
threada.start();
-
threadb.start();
-
}
-
}
运行结果
volatile 变量需要进⾏原⼦操作。 signal++ 并不是⼀个原⼦操作,所以我们需要使⽤ synchronized 给它“上锁”
2.消息传递
等待/通知机制(wait/notify):一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程。等待/通知机制使⽤的是使⽤同⼀个对象锁,如果你两个线程使⽤的是不同的对象锁,那它们之间是不能⽤等待/通知机制通信的。
wait()当前线程释放锁并进入等待(阻塞)状态,notify()唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁notifyAll()唤醒所有正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁
notify()和notifyAll()的区别:
notify()⽅法会随机叫醒⼀个正在等待的线程,⽽notifyAll()会叫醒所有正在等待的线程。
-
public
class
WaitandNotify {
-
static
boolean
flag
=
true;
-
static
Object
obj
=
new
Object();
-
static
class
ThreadA
implements
Runnable {
-
@Override
-
public
void
run
() {
-
synchronized (obj) {
-
while (flag){
-
System.out.println(
"flag为true,不满足条件,继续等待");
-
try {
-
obj.wait();
-
}
catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
System.out.println(
"flag为false,我要从wait状态返回继续执行了");
-
}
-
}
-
}
-
static
class
ThreadB
implements
Runnable {
-
@Override
-
public
void
run
() {
-
synchronized (obj) {
-
while (flag){
-
obj.notifyAll();
-
System.out.println(
"设置flag为false,我发出通知了,但是我不会立马释放锁");
-
flag =
false;
-
}
-
}
-
}
-
}
-
public
static
void
main
(String[] args) {
-
Thread
threada
=
new
Thread(
new
ThreadA());
-
Thread
threadb
=
new
Thread(
new
ThreadB());
-
threada.start();
-
threadb.start();
-
}
-
}
运行结果

3.管道流
-
public
class
WaitandNotify {
-
static
boolean
flag
=
true;
-
static
Object
obj
=
new
Object();
-
static
class
ReaderThread
implements
Runnable{
-
private PipedReader in;
-
public
ReaderThread
(PipedReader in){
-
this.in=in;
-
}
-
@Override
-
public
void
run
() {
-
System.out.println(
"this is a reader");
-
int receice=
0;
-
try {
-
while ((receice=in.read())!=-
1){
-
System.out.println(
"read "+(
char) receice);
-
}
-
}
catch (IOException ex){
-
ex.printStackTrace();
-
}
-
-
}
-
}
-
-
static
class
WriterThread
implements
Runnable{
-
private PipedWriter out;
-
public
WriterThread
(PipedWriter out){
-
this.out=out;
-
}
-
@Override
-
public
void
run
() {
-
System.out.println(
"this is a writer");
-
try {
-
out.write(
"write A");
-
}
catch (IOException ex){
-
ex.printStackTrace();
-
}
finally {
-
try {
-
out.close();
-
}
catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
}
-
public
static
void
main
(String[] args)
throws IOException {
-
PipedWriter
writer
=
new
PipedWriter();
-
PipedReader
reader
=
new
PipedReader();
-
writer.connect(reader);
-
Thread
threada
=
new
Thread(
new
ReaderThread(reader));
-
Thread
threadb
=
new
Thread(
new
WriterThread(writer));
-
threada.start();
-
threadb.start();
-
}
-
}
运行结果
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/114545.html


