Java 生产者 与 消费者 的实际运用

生产者消费者问题是研究多线程资源征用时绕不开的经典问题之一。
生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。
核心问题在于:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。在Java中多种支持同步的方法:

(1)wait() / notify()方法

(2)await() / signal()方法

(3)BlockingQueue阻塞队列方法

以我们开发的项目中的打印模块为例子。开发需求中 需要用到打印机打印小票。
打印机的资源是单一的,打印任务会抢占打印机资源。

项目中出现过这个情况:
场景:当打印机正在打印某张小票的时候,正当此时有某个任务往打印机发生另一张小票打印数据。
现象:前面一张小票还没有打印完成,就接着打印后面来到的小票。结果导致前面的小票没有打印完成,信息丢失。
期望:需等待第一张小票打印完成,再打印第二张小票。

这时候我们想到了用 队列解决这个事情。

BlockingQueue 刚刚满足我们的需求,而且用法简单。

因为打印任务是 一个需要长期存活的任务所以我们 把打印任务 用Service 接收,App启动的时候启动这个 Service ;

//前台打印机任务队列处理
public class PrintService extends Service {

    private static final String TAG = "PrintService";
    private static final LinkedBlockingQueue ticketQueue = new LinkedBlockingQueue<>();
    private boolean flag = true;//退出循环

    @Override
    public void onCreate() {
        if (PrinterUtil.getInstance(this).GetUsbStatus())
            PrinterUtil.writeData(this, "打印测试");
        else {
            PrinterUtil.getInstance(this).Openusb();
        }
        flag = true;
        super.onCreate();
    }

    public PrintService() {
        EventBus.getDefault().register(this);
        print();
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

 // 接收外部发过来的打印任务,并且放到打印队列中。
    @Subscriber
    public void onEvent(PrintEvent printEvent) {
        try {
            ticketQueue.put(printEvent);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 阻塞方法 当队列有元素的时候才会打印 ,获取打印数据,并从队列移除。
     *
     * @return PrintEvent
     */
    private PrintEvent getTicket() {
        try {
            return ticketQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        }
    }

    private void print() {
        MyLog.e(TAG, "print" + "");
        new Thread(() -> {
        //死循环 不断从队列中获取打印任务
            while (flag) {
                PrintEvent printEvent = getTicket();
                if (printEvent == null || printEvent.getTicket() == null) {
                    continue;
                }
                //打印
                Ticket ticket = printEvent.getTicket();
                       ticket.print();

            }
        }).start();
    }


    @Override
    public void onDestroy() {
        flag = false;
        super.onDestroy();
    }
}

到此我们的打印队列及打印已经设计完成。
这样每次等上一次打印任务完成了才会从队列获取下一个打印任务。
就不会出现以上的情况。
注意:当打印队列为空的时候 ,打印线程会阻塞,有数据的时候打印线程继续。这就类似生产者与消费者的模式了。

更多精彩内容:
http://jblog.top/

你可能感兴趣的:(android,java)