Java层使用pipe完善阻塞式编程

Java层使用pipe完善阻塞式编程

背景

java层while循环,如果是非阻塞的循环,会极度浪费cpu资源,也会导致耗电严重,app被吐槽。

Android系统层一般会使用消息通知机制,比如:

looper机制,无消息时就会阻塞。

linux IO多路复用

linux pipe管道

具体的就不多说了,我们今天的主题是java层使用pipe

java层有很多阻塞类可使用,比如ConditionVariable

通过源代码代码可以看到,block函数其实使用了wait, notify。

作用:ConditionVariable其实是在一个线程加锁,同一个线程调用open解锁,其他线程调用block函数等待锁打开

package android.os;

/**
 * Class that implements the condition variable locking paradigm.
 *
 * <p>
 * This differs from the built-in java.lang.Object wait() and notify()
 * in that this class contains the condition to wait on itself.  That means
 * open(), close() and block() are sticky.  If open() is called before block(),
 * block() will not block, and instead return immediately.
 *
 * <p>
 * This class uses itself is at the object to wait on, so if you wait()
 * or notify() on a ConditionVariable, the results are undefined.
 */
public class ConditionVariable
  {
    private volatile boolean mCondition;

    /**
     * Create the ConditionVariable in the default closed state.
     */
    public ConditionVariable()
    {
        mCondition = false;
    }
 
    /**
     * Create the ConditionVariable with the given state.
     *
     * <p>
     * Pass true for opened and false for closed.
     */
    public ConditionVariable(boolean state)
    {
        mCondition = state;
    }
    public void open()
    { 
        synchronized (this) {
            boolean old = mCondition;
            mCondition = true;
            if (!old) {
                this.notifyAll();
            }
        }
    }

    /**
     * Reset the condition to the closed state.
     *
     * <p>
     * Any threads that call block() will block until someone calls open.
     */
    public void close()
    {
        synchronized (this) {
            mCondition = false;
        }
    }

    /**
     * Block the current thread until the condition is opened.
     *
     * <p>
     * If the condition is already opened, return immediately.
     */
    public void block()
    {
        synchronized (this) {
            while (!mCondition) {
                try {
                    this.wait();
                }
                catch (InterruptedException e) {
                }
            }
        }
    }

    /**
     * Block the current thread until the condition is opened or until
     * timeout milliseconds have passed.
     *
     * <p>
     * If the condition is already opened, return immediately.
     *
     * @param timeout the minimum time to wait in milliseconds.
     *
     * @return true if the condition was opened, false if the call returns
     * because of the timeout.
     */
    public boolean block(long timeout)
    {
        // Object.wait(0) means wait forever, to mimic this, we just
        // call the other block() method in that case.  It simplifies
        // this code for the common case.
        if (timeout != 0) {
            synchronized (this) {
                long now = System.currentTimeMillis();
                long end = now + timeout;
                while (!mCondition && now < end) {
                    try {
                        this.wait(end-now);
                    }
                    catch (InterruptedException e) {
                    }
                    now = System.currentTimeMillis();
                }
                return mCondition;
            }
        } else {
            this.block();
            return true;
        }
    }
}


今天,我们使用一种更原生的方式,java也支持管道通讯,可实现阻塞编程

代码地址: https://github.com/whulzz1993/AndroidDemo/tree/master

如何创建管道?

通过android.os.ParcelFileDescriptor.createPipe返回fd[2],然后使用fd[0]作为read, fd[1]作为write

package com.example.javapipe;

import android.os.ParcelFileDescriptor;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class JavaPipe {
    private static final String TAG = "JavaPipe";
    InputStream mPipeRead = null;
    OutputStream mPipeWrite = null;
    public JavaPipe() {
        initPipe();
    }
    private void initPipe() {
        try {
            ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();
            mPipeRead = new ParcelFileDescriptor.AutoCloseInputStream(pipes[0]);
            mPipeWrite = new ParcelFileDescriptor.AutoCloseOutputStream(pipes[1]);
        } catch (IOException e) {
            Log.e(TAG, "initPipe failed!", e);
            mPipeRead = null;
            mPipeWrite = null;
        }
    }

    public void pipeRead() {
        if (mPipeRead != null) {
            int tryCount = 3;
            do {
                try {
                    mPipeRead.read();
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            } while (--tryCount > 0);
        }
    }

    public void pipeWrite() {
        if (mPipeWrite != null) {
            int tryCount = 3;
            do {
                try {
                    mPipeWrite.write(1);
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            } while (--tryCount > 0);
        }
    }
}

如何在代码中使用

可以直接new Javapipe,然后在while循环中读取管道消息进行阻塞

    private void testPipe() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    long start = System.currentTimeMillis();
                    mPipe.pipeRead();
                    Log.d(TAG, String.format("pipeRead success cost %dms",
                            System.currentTimeMillis() - start));
                }
            }
        }).start();
    }

如果不往管道中写,则会一直阻塞下去

我测试的时候是通过点击按钮触发通道写入的

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
                //通道写消息
                mPipe.pipeWrite();
            }
        });
        mPipe = new JavaPipe();
        testPipe();
    }

看一下点击按钮的log:

2021-03-19 20:00:21.462 31471-31517/com.example.demo D/MainActivity: pipeRead success cost 13691ms
2021-03-19 20:00:27.621 31471-31517/com.example.demo D/MainActivity: pipeRead success cost 6159ms
2021-03-19 20:00:39.938 31471-31517/com.example.demo D/MainActivity: pipeRead success cost 12317ms
2021-03-19 20:22:28.041 31471-31517/com.example.demo D/MainActivity: pipeRead success cost 1308101ms
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值