zoukankan      html  css  js  c++  java
  • Java并发编程的艺术(七)——线程间的通信

    为什么需要线程间通信

    让线程之间合作,提高运行效率。

    volatile和synchronized关键字

    实现原理

    这两个方式都是采用共享内存的方式进行通信,通过同步机制保证数据可见性和排他性。

    特点

    • 本质是数据共享。
    • 不能特定地传给某个线程数据,需要程序员自己编写逻辑。数据在各个线程的更新顺序由操作系统决定。
    • 不能过多使用,这样会降低程序执行效率。

    使用案例

    // 用于控制线程当前的执行状态
    private volatile boolean flag = false;
    
    // 开启一条线程
    Thread t1 = new Thread(new Runnable(){
        void run(){
            // 开关
            while(!flag){
                Thread.sleep(1000);
            }
            // 执行线程任务
            doSometing();
        }
    }).start();
    
    // 开始执行
    public void start(){
        flag = true;
    }
    

    这里通过volatile修饰的标志位flag实现其他线程对t1的控制。

    等待和通知机制

    等待/通知是Java实现多个进程交替协作的机制。

    实现方法

    Java提供了API实现该机制。
    在这里插入图片描述

    使用注意

    • 上述所有方法都必须放在一个同步块中。
    • 上述方法都只能由所处同步块的锁对象调用。
    • 调用notify()方法之后,只是将线程从等待队列中转移到阻塞队列,当线程得到锁之后,才能用wait()方法之后,继续执行程序。

    经典范式

    该范式分为两个部分,分别针对等待方(消费者)和通知方(生产者)。

    生产者通过notify唤醒消费者。消费者通过wait等待生产者生产完毕。

    生产者:

    private volatile boolean flag = false;
    
    synchronized(objectA) {
    	flag = true;
    	objectA.notify();
    }
    

    消费者:

    synchronized(objectA) {
    	while(!flag) {
    		objectA.wait();
    	}
    
    	doSomething();
    }
    

    超时等待

    为了避免等待方无止境地等待,可以通过超时等待,跳出等待。

    public void get(long mills){
        synchronized( list ){
            // 不加超时功能
            if ( mills <= 0 ) {
                while( list.isEmpty() ){
                    list.wait();
                }
            }
    
            // 添加超时功能
            else {
                boolean isTimeout = false;
                while(list.isEmpty() && isTimeout){
                    list.wait(mills);
                    isTimeout = true;
                }
    
                // doSometing……
            }
        }
    }
    

    代码中利用list作为中间变量装载数据。

    管道流

    什么是管道流

    用于线程间的数据传输。传输媒介为内存。

    实现方式

    管道输入输出主要包括四种具体实现:PipedOutputStream、PipedInputStream、PipedWriter、PipedReader。分别对应字节流和字符流。

    // 创建输入流与输出流对象
    PipedWriter out = new PipedWriter();
    PipedReader in = new PipedReader();
    
    // 连接输入输出流
    out.connect(in);
    
    // 创建写线程
    class WriteThread extends Thread{
        private PipedWriter out;
    
        public WriteThread(PipedWriter out){
            this.out = out;
        }
    
        public void run(){
            out.write("lippon");
        }
    }
    
    // 创建读线程
    class ReaderThread extends Thread{
        private PipedReader in;
    
        public ReaderThread(PipedReader in){
            this.in = in;
        }
    
        public void run(){
            in.read();
        }
    }
    
    

    Thread.join

    作用

    1. 让多个并发的线程串行执行。
    2. 当A线程调用B.jion(),那么,A会等待B结束后,再从jion继续执行。
    3. 如果被等待的线程执行很长的时间,那么join会抛出InterruptedException。当调用B.interrupt()之后,jion函数就会抛出异常。

    实现原理

    1. join的底层采用wait() 方法进行停止运行。
    2. 然后当被等待线程终止后,会调用线程的notifyAll() 方法释等待队列中的线程。

    实现方式

    public static void main(String[] args){
    
        // 开启一条线程
        Thread t = new Thread(new Runnable(){
            public void run(){
                // doSometing
            }
        }).start();
    
        // 调用join,等待t线程执行完毕
        try{
            t.join();
        }catch(InterruptedException e){
            // 中断处理……
        }
    }
    
  • 相关阅读:
    Android移动view动画问题
    GIT常用操作
    linux下mysql安装
    jdk安装
    linux下Tomcat安装
    猜测性能瓶颈
    MySQL没有远程连接权限设置
    linux下jmeter使用帮助
    BI的核心价值[转]
    BI与大数据
  • 原文地址:https://www.cnblogs.com/lippon/p/14117663.html
Copyright © 2011-2022 走看看