• 使用LinkedBlockingQueue来实现生产者消费者的例子


    工作中,经常有将文件中的数据导入数据库的表中,或者将数据库表中的记录保存到文件中。为了提高程序的处理速度,可以设置读线程和写线程,这些线程通过消息队列进行数据交互。本例就是使用了LinkedBlockingQueue来模仿生产者线程和消费者线程进行数据生产和消费。
    为了方便,这些不同的类被写在了一个类中,实际使用的时候,可以单独拆开,举一反三地使用。

    以下是例子:

    LinkedBlockingQueueDemo.java

    import java.util.Date;
    import java.util.Random;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.TimeUnit;
     
    public class LinkedBlockingQueueDemo {
        // 生产者线程数量
        private final static int providerThreadAmount = 5;
     
        // 记录每一个生产者线程是否处理完毕的标记
        private static boolean[] providerDoneFlag = new boolean[providerThreadAmount];
     
        // 整个所有的生产者线程全部结束的标记
        private static boolean done = false;
     
        // 一个线程安全的队列,用于生产者和消费者异步地信息交互
        private static LinkedBlockingQueue<String> linkedBlockingQeque = new LinkedBlockingQueue<String>();
     
        static class ProviderThread extends Thread {
            private Thread thread;
            private String threadName;
            private int threadNo;
     
            public ProviderThread(String threadName2, int threadNo) {
                this.threadName = threadName2;
                this.threadNo = threadNo;
            }
     
            public void start() {
                if (thread == null) {
                    thread = new Thread(this, threadName);
                }
     
                thread.start();
                System.out.println(
                        (new Date().getTime()) + " " + threadName + " starting... " + Thread.currentThread().getName());
            }
     
            @Override
            public void run() {
                int rows = 0;
                for (int i = 0; i < 100; i++) {
                    String string = String.format("%s-%d-%s", threadName, i, Thread.currentThread().getName());
                    // offer不会去阻塞线程,put会
                    //linkedBlockingQeque.offer(string);
                    linkedBlockingQeque.put(string);
                    rows++;
                    /*
                     * try { Thread.sleep((new Random()).nextInt(5) * 1000); } catch
                     * (InterruptedException e) { e.printStackTrace(); }
                     */
                }
     
                // 本线程处理完毕的标记
                LinkedBlockingQueueDemo.providerDoneFlag[threadNo] = true;
                System.out.println((new Date().getTime()) + " " + threadName + " end. total rows is " + rows + "	"
                        + Thread.currentThread().getName());
            }
        }
     
        static class ConsumerThread implements Runnable {
            private Thread thread;
            private String threadName;
     
            public ConsumerThread(String threadName2) {
                this.threadName = threadName2;
            }
     
            public void start() {
                if (thread == null) {
                    thread = new Thread(this, threadName);
                }
     
                thread.start();
                System.out.println(
                        (new Date().getTime()) + " " + threadName + " starting... " + Thread.currentThread().getName());
            }
     
            @Override
            public void run() {
                int rows = 0;
                // 生产者线程没有结束,或者消息队列中有元素的时候,去队列中取数据
                while (LinkedBlockingQueueDemo.getDone() == false || linkedBlockingQeque.isEmpty() == false) {
                    try {
                        //在甘肃电信的实际应用中发现,当数据的处理量达到千万级的时候,带参数的poll会将主机的几百个G的内存耗尽,jvm会提示申请内存失败,并将进程退出。网上说,这是这个方法的一个bug。
                        //String string = linkedBlockingQeque.poll(3, TimeUnit.SECONDS);
                        String string = linkedBlockingQeque.poll();
                        if (string == null) {
                            continue;
                        }
     
                        rows++;
     
                        System.out
                                .println((new Date().getTime()) + " " + threadName + " get msg from linkedBlockingQeque is "
                                        + string + "	" + Thread.currentThread().getName());
                        /*
                         * try { Thread.sleep((new Random()).nextInt(5) * 1000); } catch
                         * (InterruptedException e) { e.printStackTrace(); }
                         */
     
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
     
                }
                System.out.println((new Date().getTime()) + " " + threadName + " end total rows is " + rows + "	"
                        + Thread.currentThread().getName());
            }
        }
     
        public static synchronized void setDone(boolean flag) {
            LinkedBlockingQueueDemo.done = flag;
        }
        
        public static synchronized boolean getDone() {
            return LinkedBlockingQueueDemo.done;
        }
     
        public static void main(String[] args) {
            System.out.println((new Date().getTime()) + " " + "process begin at " + Thread.currentThread().getName());
            System.out.println(
                    (new Date().getTime()) + " " + "linkedBlockingDeque.hashCode() is " + linkedBlockingQeque.hashCode());
     
            // 启动若干生产者线程
            for (int i = 0; i < providerThreadAmount; i++) {
                String threadName = String.format("%s-%d", "ProviderThread", i);
                ProviderThread providerThread = new ProviderThread(threadName, i);
                providerThread.start();
            }
     
            // 启动若干个消费者线程
            for (int i = 0; i < 10; i++) {
                String threadName = String.format("%s-%d", "ConsumerThread", i);
                ConsumerThread consumerThread = new ConsumerThread(threadName);
                consumerThread.start();
            }
     
            // 循环检测生产者线程是否处理完毕
            do {
                for (boolean b : providerDoneFlag) {
                    if (b == false) {
                        /*
                         * try { Thread.sleep(3 * 1000); System.out.println((new Date().getTime()) +
                         * " "+"sleep 3 seconds. linkedBlockingQeque.size() is "+linkedBlockingQeque.
                         * size() + "	" + Thread.currentThread().getName()); } catch
                         * (InterruptedException e) { e.printStackTrace(); }
                         */
     
                        // 只要有一个生产者线程没有结束,则整个生产者线程检测认为没有结束
                        break;
                    }
     
                    LinkedBlockingQueueDemo.setDone(true);
                }
     
                // 生产者线程全部结束的时候,跳出检测
                if (LinkedBlockingQueueDemo.getDone() == true) {
                    break;
                }
            } while (true);
     
            System.out.println((new Date().getTime()) + " process done successfully	" + Thread.currentThread().getName());
        }
    }

    结果略。

  • 相关阅读:
    数字签名(代码签名)流程
    (转)__cdecl __fastcall与 __stdcall
    装修主材
    ATL 获取flash信息
    Windows结构化异常
    格式化HRESULT获取对应文本
    which type of VS files should be committed into a version control system
    读Windows核心编程-5-作业
    IE WebBrowser事件触发
    Windows 结构化异常
  • 原文地址:https://www.cnblogs.com/babyha/p/9765846.html
Copyright © 2020-2023  润新知