线程间的通讯

线程间的通讯线程通信是为了在多线程操作同一数据时协调线程状态 防止资源浪费

大家好,欢迎来到IT知识分享网。

一.为什么需要线程通讯

线程是操作系统调度的最小单位,有自己的栈空间,可以按照既定的代码逐步的执行,但是如果每个线程间都孤立的运行,那就会造资源浪费。所以在现实中,我们需要这些线程间可以按照指定的规则共同完成一件任务,所以这些线程之间就需要互相协调,这个过程被称为线程的通信。

线程间的通讯定义:多个线程在操作同一份数据时,互相告知自己的状态,避免对同一共享变量的争夺。 

二.线程间的通讯方式

线程通讯的方式主要可以分为三种方式,共享内存消息传递管道流。

 1.共享内存

        (1)同步–synchronized

线程同步是线程之间按照⼀定的顺序执⾏,可以使⽤锁来实现达到线程同步,也就是在需要同步的代码块里加上关键字synchronized 。因为⼀个锁同⼀时间只能被⼀个线程持有。

synchronized可以修饰方法或者以同步块,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

 
    
  1. public class SynchronizedTest {
  2. static Object obj = new Object();
  3. static class ThreadA implements Runnable{
  4. @Override
  5. public void run () {
  6. synchronized (obj){
  7. for ( int i = 0; i < 5; i++) {
  8. System.out.println( "ThreadA" + i);
  9. }
  10. }
  11. }
  12. }
  13. static class ThreadB implements Runnable{
  14. @Override
  15. public void run () {
  16. synchronized (obj){
  17. for ( int i = 0; i < 5; i++) {
  18. System.out.println( "ThreadB" + i);
  19. }
  20. }
  21. }
  22. }
  23. public static void main (String[] args) {
  24. Thread threada = new Thread( new ThreadA());
  25. Thread threadb = new Thread( new ThreadB());
  26. threada.start();
  27. threadb.start();
  28. }
  29. }
线程间的通讯

运行结果

线程间的通讯 

 线程A和线程B需要访问同一个对象lock,谁获得锁,谁就先执行。线程B要等线程A执行完再执行,所以是同步的,这就实现了线程间的通信

      (2)信号量 –volatile

  1. 线程A把本地内存A更新过的共享变量刷新到主内存中
  2. 线程B到内存中去读取线程A之前已更新过的共享变量。

为保证线程间的通信必须经过主内存。需要关键字volatile。

volatile保证内存可见性,即多个线程访问内存中的同一个被volatile关键字修饰的变量时,当某一个线程修改完该变量后,需要先将这个最新修改的值写回到主内存,从而保证下一个读取该变量的线程取得的就是主内存中该数据的最新值,这样就保证线程之间的透明性,便于线程通信。

 

 
    
  1. public class VolatileTest {
  2. static volatile int s = 0;
  3. static class ThreadA implements Runnable {
  4. @Override
  5. public void run () {
  6. while (s < 10) {
  7. if (s % 2 == 0) {
  8. System.out.println( "ThreadA: " + s);
  9. synchronized ( this) {
  10. s++;
  11. }
  12. }
  13. }
  14. }
  15. }
  16. static class ThreadB implements Runnable {
  17. @Override
  18. public void run () {
  19. while (s < 10) {
  20. if (s % 2 == 1) {
  21. System.out.println( "ThreadB: " + s);
  22. synchronized ( this) {
  23. s++;
  24. }
  25. }
  26. }
  27. }
  28. }
  29. public static void main (String[] args) {
  30. Thread threada = new Thread( new ThreadA());
  31. Thread threadb = new Thread( new ThreadB());
  32. threada.start();
  33. threadb.start();
  34. }
  35. }
线程间的通讯

运行结果

线程间的通讯

volatile 变量需要进⾏原⼦操作。 signal++ 并不是⼀个原⼦操作,所以我们需要使⽤ synchronized 给它“上锁” 

 2.消息传递

等待/通知机制(wait/notify):一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程。等待/通知机制使⽤的是使⽤同⼀个对象锁,如果你两个线程使⽤的是不同的对象锁,那它们之间是不能⽤等待/通知机制通信的。

wait()当前线程释放锁并进入等待(阻塞)状态,notify()唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁notifyAll()唤醒所有正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁 

notify()和notifyAll()的区别:
notify()⽅法会随机叫醒⼀个正在等待的线程,⽽notifyAll()会叫醒所有正在等待的线程。

 

 
    
  1. public class WaitandNotify {
  2. static boolean flag = true;
  3. static Object obj = new Object();
  4. static class ThreadA implements Runnable {
  5. @Override
  6. public void run () {
  7. synchronized (obj) {
  8. while (flag){
  9. System.out.println( "flag为true,不满足条件,继续等待");
  10. try {
  11. obj.wait();
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. System.out.println( "flag为false,我要从wait状态返回继续执行了");
  17. }
  18. }
  19. }
  20. static class ThreadB implements Runnable {
  21. @Override
  22. public void run () {
  23. synchronized (obj) {
  24. while (flag){
  25. obj.notifyAll();
  26. System.out.println( "设置flag为false,我发出通知了,但是我不会立马释放锁");
  27. flag = false;
  28. }
  29. }
  30. }
  31. }
  32. public static void main (String[] args) {
  33. Thread threada = new Thread( new ThreadA());
  34. Thread threadb = new Thread( new ThreadB());
  35. threada.start();
  36. threadb.start();
  37. }
  38. }
线程间的通讯

运行结果

线程间的通讯 

3.管道流

 
    
  1. public class WaitandNotify {
  2. static boolean flag = true;
  3. static Object obj = new Object();
  4. static class ReaderThread implements Runnable{
  5. private PipedReader in;
  6. public ReaderThread (PipedReader in){
  7. this.in=in;
  8. }
  9. @Override
  10. public void run () {
  11. System.out.println( "this is a reader");
  12. int receice= 0;
  13. try {
  14. while ((receice=in.read())!=- 1){
  15. System.out.println( "read "+( char) receice);
  16. }
  17. } catch (IOException ex){
  18. ex.printStackTrace();
  19. }
  20. }
  21. }
  22. static class WriterThread implements Runnable{
  23. private PipedWriter out;
  24. public WriterThread (PipedWriter out){
  25. this.out=out;
  26. }
  27. @Override
  28. public void run () {
  29. System.out.println( "this is a writer");
  30. try {
  31. out.write( "write A");
  32. } catch (IOException ex){
  33. ex.printStackTrace();
  34. } finally {
  35. try {
  36. out.close();
  37. } catch (IOException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }
  42. }
  43. public static void main (String[] args) throws IOException {
  44. PipedWriter writer = new PipedWriter();
  45. PipedReader reader = new PipedReader();
  46. writer.connect(reader);
  47. Thread threada = new Thread( new ReaderThread(reader));
  48. Thread threadb = new Thread( new WriterThread(writer));
  49. threada.start();
  50. threadb.start();
  51. }
  52. }
线程间的通讯

 运行结果

线程间的通讯

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/114545.html

(0)
上一篇 2025-12-08 13:00
下一篇 2025-12-08 13:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信