Java线程之间通信方式

这篇具有很好参考价值的文章主要介绍了Java线程之间通信方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


1 线程之间的通信方式主要有以下几种

Java线程之间通信方式,java,java,开发语言

在实际开发时,一个进程中往往有很多个线程,大多数线程之间往往不是绝对独立的,比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上,又或者比较典型的消费者-生产者模式,在这些场景下,线程间通信成了我们必须使用的手段,那么线程之间怎么通信呢?

线程间通信方式,从实现本质来讲,主要可以分为两大类共享内存和消息传递。

相信大家还记得,在内存模型一节,我们提到多线程并发情况下的三大特性,原子性,有序性,可见性,其所对应的解决方案就可以用来实现线程间通信,这些解决方案的本质就是共享内存。

对于消息传递而言,最经典的实现就是我们的Handler机制,在子线程使用主线程的Handler对象将一些信息发送到主线程以便进行处理。

下面我们来看一些线程间通信的典型实现

2 共享变量

共享变量:线程之间可以通过共享变量来进行通信。不同的线程可以共享同一个变量,并在变量上进行读写操作。需要注意的是,共享变量可能会引发线程安全问题,需要通过同步机制来确保线程安全。

public class SharedData {
    private int value;
    public synchronized int getValue() { 
        return value; 
    }
    public synchronized void setValue(int value) { 
        this.value = value; 
    }
}

​ 在这个示例中,定义了一个共享数据类 SharedData,其中包含一个整型变量 value 和两个同步方法 getValue()setValue(),用于获取和设置变量的值。由于这两个方法都是同步的,因此多个线程可以安全地访问该变量。

public class SharedDataExample {
    public static void main(String[] args) throws InterruptedException {
        SharedData sharedData = new SharedData();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                sharedData.setValue(i);
                System.out.println(Thread.currentThread().getName() + " write " + sharedData.getValue());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " read " + sharedData.getValue());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
    }
}

​ 在这个示例中,创建了两个线程分别用于读写共享数据 SharedData,多次执行该示例可以看到控制台输出表明两个线程在安全地访问共享变量。

结果如图:
Java线程之间通信方式,java,java,开发语言

3 锁机制

锁机制:锁机制是一种常用的线程同步机制,可以保证在同一时间只有一个线程能够访问共享资源。Java提供了多种锁类型,如 synchronized 关键字、ReentrantLock 类等。

public class LockExample {
    private static Lock lock = new ReentrantLock();
    private static int count = 0;
    private static void increase() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                increase();
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                increase();
            }
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(count);
    }
}

​ 在这个示例中,使用了 Lock 接口和 ReentrantLock 类来对计数器进行同步,多次执行该示例可以看到最终输出的计数器值为 20000。

结果如图:
Java线程之间通信方式,java,java,开发语言

4 条件变量

条件变量:条件变量是一种线程间通信机制,它用于在一个共享资源上等待某个条件的成立。Java 提供了 Condition 接口来支持条件变量的实现,在使用 Condition 时需要先获取锁,然后调用 await() 方法等待条件成立,当条件成立时可以通过 signal() 或 signalAll() 方法唤醒等待该条件的线程。

public class ConditionExample {
    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    private static int count = 0;
    private static void await() throws InterruptedException {
        lock.lock();
        try {
            condition.await();
        } finally {
            lock.unlock();
        }
    }
    private static void signal() {
        lock.lock();
        try {
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count++;
                System.out.println(Thread.currentThread().getName() + " increase count to " + count);
                if (count == 5) {
                    signal();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                await();
                System.out.println(Thread.currentThread().getName() + " receive signal, count is " + count);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
    }
}

​ 在这个示例中,使用了 Lock 接口和 Condition 接口来定义了一个计数器,线程1每次增加计数器的值并判断是否达到条件,当计数器达到条件时调用 signal() 方法通知线程2,线程2等待条件成立后执行相应的操作。

Java线程之间通信方式,java,java,开发语言

5 信号量

信号量:信号量是一种常见的线程同步机制,可用于控制多个线程对共享资源的访问。Java 提供了 Semaphore 类来实现信号量,Semaphore 类有两个常用的方法 acquire() 和 release(),分别用于获取和释放信号量。

public class SemaphoreExample {
    private static Semaphore semaphore = new Semaphore(2);
    private static void doWork() throws InterruptedException {
        semaphore.acquire();
        System.out.println(Thread.currentThread().getName() + " start working");
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + " finish working");
        semaphore.release();
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            try {
                doWork();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                doWork();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread thread3 = new Thread(() -> {
            try {
                doWork();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread1.start();
        thread2.start();
        thread3.start();
        thread1.join();
        thread2.join();
        thread3.join();
    }
}

​ 在这个示例中,使用了 Semaphore 类来定义了一个信号量,线程1、线程2、线程3都需要获取信号量才能进行工作,每次执行 doWork() 方法需要占用资源,执行完毕后释放信号量。

Java线程之间通信方式,java,java,开发语言

6 管道

管道:管道是一种用于线程间通信的高级机制,它可以实现一个线程向另一个线程传送数据。Java 提供了 PipedInputStream 和 PipedOutputStream 两个类来支持管道的实现,其中 PipedInputStream 用于读取数据,PipedOutputStream 用于写入数据。

public class PipeExample {
    static class WriterThread extends Thread {
        private PipedOutputStream output;
        WriterThread(PipedOutputStream output) {
            this.output = output;
        }
        @Override
        public void run() {
            try {
                for(int i=1;i<=10;i++) {
                    output.write(i);
                    System.out.println("写入数据:" + i);
                    Thread.sleep(1000);
                }
            } catch(Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    output.close();
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    static class ReaderThread extends Thread {
        private PipedInputStream input;
        ReaderThread(PipedInputStream input) {
            this.input = input;
        }
        @Override
        public void run() {
            try {
                int value;
                while((value=input.read()) != -1) {
                    System.out.println("读取数据:" + value);
                }
            } catch(Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    input.close();
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws IOException {
        PipedOutputStream output = new PipedOutputStream();
        PipedInputStream input = new PipedInputStream(output);
        Thread thread1 = new WriterThread(output);
        Thread thread2 = new ReaderThread(input);
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,使用了 PipedOutputStream 类和 PipedInputStream 类来定义了一个管道,线程1向管道中写入数据,线程2从管道中读取数据,通过管道来实现两个线程之间的通信。

运行结果:Java线程之间通信方式,java,java,开发语言

需要注意的是,以上通信方式都需要在多线程程序中谨慎使用,需要考虑线程安全和性能等方面的问题。为了确保程序正确、高效地运行,需要根据具体情况选择合适的线程通信方式,并进行相应的测试和优化。

6 join方法的实现原理

说了这么多,也举了这么多例子了,join方法是怎么实现线程等待的呢?我点进去join方法内部可以看到,其实它的内部也就是调用了wait()方法,

Java线程之间通信方式,java,java,开发语言

只不过它多做了一步,用了一个循环来判断线程是否还活着,isAlive()方法就是用来判断线程是否还活着;

Java线程之间通信方式,java,java,开发语言

7 join方法实现顺序性原理

那么这个时候肯定有的同学就有疑问了,只看到join()方法调用了wait()方法,但是没看到有调用notify() 或者 notifyAll() 系列的唤醒方法,那它是怎么唤醒的呢?如果不唤醒,那不就一直等待下去了吗?

*原来啊,在java中,Thread类线程执行完run()方法后,一定会自动执行notifyAll()方法*

这是notifyAll()非常重要的隐藏知识点,这个细节隐藏在Java的Native方法中,所以一般不会被人发现。我们观察C/C++源码,如下:


oid JavaThread::exit(booldestory_vm, ExitTypeexit_type);
static void ensure_join(JavaThread*thread) {
	Handle threadObj(thread, thread -> threadObj());
	ObjectLocker lock(threadObj, thread);
	thread -> clear_pending_exception();
	java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
	java_lang_Thread::set_thread(threadObj(), NULL);
     //下行执行了notifyAll()操作
	lock.notify_all(thread);
	thread -> clear_pending_exception();
	}

其中ensure_join就是执行join()方法,等方法执行结束时,此行代码lock.notify_all(thread);意思是通过notifyAll()唤醒了所有等待线程。所以在使用线程的时候,要特别注意文章来源地址https://www.toymoban.com/news/detail-704537.html

到了这里,关于Java线程之间通信方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java死锁、线程状态、线程通信、线程池

    java实现多线程: [1]继承Thread类并重写run方法 [2]实现Runnable接口 线程Thread中常用的方法: setName(): Thread.currentThread().getName(): ​ static void sleep(); static void yield(): join(): setDeamon()设置后台线程 线程安全问题: ---当多个线程共享同一个资源时,对该资源的操作就会出现线程安全问题。

    2024年02月13日
    浏览(39)
  • [Java]线程生命周期与线程通信

    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18162522 出自【进步*于辰的博客】 线程生命周期与进程有诸多相似,所以我们很容易将两者关联理解并混淆,一些细节之处确有许多不同,因为线程调度与进程调度虽都由

    2024年04月27日
    浏览(36)
  • Java 进阶(12) 线程通信

    多个线程在处理同⼀个资源,但是处理的动作(线程的任务)却不相同。 为什么要处理线程间通信 多个线程并发执⾏时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成⼀件任务,并且我们希望他们有规律的执⾏, 那么多线程之间需要⼀些协调通信,以此

    2023年04月16日
    浏览(36)
  • 【Java】详解多线程通信

    🌺 个人主页: Dawn黎明开始 🎀 系列专栏: Java ⭐ 每日一句:什么都不做,才会来不及 📢 欢迎大家:关注 🔍+ 点赞 👍+评论 📝+收藏⭐️ 文章目录 🔐多线程通信 (1).🔓由来 (2).🔓成员方法  (3).🔓案例引入 (4).🔓代码实现       现代社会崇尚合作精神,分工合作在日常

    2024年02月05日
    浏览(43)
  • Java多线程 - Java创建线程的4种方式

    1. Java创建线程有哪几种方式? 一个线程在Java中使用一个Thread实例来描述。Thread类是Java语言的一个重要的基础类,位于java.lang包中。Thread类有不少非常重要的属性和方法,用于存储和操作线程的描述信息。 Thread类的构造方法: 1.1 线程创建方法一:继承Thread类创建线程类 (

    2023年04月08日
    浏览(41)
  • 深入理解Java线程间通信

    合理的使用Java多线程可以更好地利用服务器资源。一般来讲,线程内部有自己私有的线程上下文,互不干扰。但是当我们需要多个线程之间相互协作的时候,就需要我们掌握Java线程的通信方式。本文将介绍Java线程之间的几种通信原理。 在Java中,锁的概念都是基于对象的,

    2024年02月09日
    浏览(48)
  • java 线程安全问题 三种线程同步方案 线程通信(了解)

    线程安全问题指的是,多个线程同时操作同一个共享资源的时候,可能会出现业务安全问题。 下面代码演示上述问题,先定义一个共享的账户类: 在定义一个取钱的线程类 最后,再写一个测试类,在测试类中创建两个线程对象 某个执行结果: 为了解决前面的线程安全问题,

    2024年02月09日
    浏览(44)
  • 面试官:Java 线程有哪几种状态?它们之间是怎么切换的?

    来源:https://blog.csdn.net/limenghua9112/article/details/106975105 线程是 JVM 执行任务的最小单元,理解线程的状态转换是理解后续多线程问题的基础。 在 JVM 运行中,线程一共有 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED 六种状态,这些状态对应 Thread.State 枚举类中的状态。 推荐

    2024年02月12日
    浏览(52)
  • 多线程之间如何进行通信 ?

    实现多线程之间通信的方式有多种,以下是一些常见的方式: 共享变量:多个线程共享一个变量,通过互斥锁(如 synchronized )来保护对该变量的访问,确保线程之间的安全通信。 wait() 和 notify() / notifyAll() :通过 Object 类的 wait() 方法使线程等待,然后使用 notify() 或

    2024年02月09日
    浏览(42)
  • Java——》线程间是如何通信的

    推荐链接:     总结——》【Java】     总结——》【Mysql】     总结——》【Redis】     总结——》【Kafka】     总结——》【Spring】     总结——》【SpringBoot】     总结——》【MyBatis、MyBatis-Plus】     总结——》【Linux】     总结——》【MongoDB】    

    2024年02月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包