通过消息队列解决多线程并发安全问题

我现在遇到的问题是:用户使用客户端扫码装箱,多个机器同时工作,出现箱号同时被多个机器选中,机器操作完成后会将箱号删除,导致其他选中此箱号的机器所有与箱号有关的操作失败。

解决方法:通过消息队列的技术,将箱号放入队列中,机器扫码时调用方法获取箱号前判断队列是否为空,为空则先添加箱号。

package cn.tedu.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

public class QueueTest2 implements Runnable {
    private static Integer a = 1;

    // 多线程数量:模拟产线数量
    private static final Integer THREAD_COUNT = 10;

    private static ArrayList list = new ArrayList();

    /**
     * 创建队列,最大容量10,LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列,即可以从队列的两端插入和移除元素。
     */
    public static BlockingQueue queue = new LinkedBlockingDeque(20);

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        // 创建线程,模拟多线程频繁访问队列,从队列中取出数据
        for (int i = 0; i < THREAD_COUNT; i++) {
            // 线程开始工作
            new Thread(new QueueTest2()).start();
        }

        // 阻塞主线程,等待子线程执行完毕后才继续执行主线程
        // Thread.sleep(1000); // 方法1。实际项目中不可取
        // t1.join(); //方法2。只有一个子线程时可用

        // 方法三。 常用
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }

        System.err.println(list.size());

        Integer[] arr = list.toArray(new Integer[0]);
        Arrays.sort(arr);
        System.err.println(arr.length);

        // 判断是否重复消费据
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (list.get(i) == list.get(j)) {
                    System.err.println("重复:" + arr[i]);
                }
            }
        }
        long last = System.currentTimeMillis();
        System.err.println("时长: " + (last - start));
    }

    /**
     * @doWith 插入数据到队列
     * @date 2019年11月12日 下午2:07:57
     * @author Sir.Yang
     */
    private static void putQueue() {
        for (int i = 0; i < 10; i++) {
            synchronized (QueueTest2.class) {
                boolean tag = queue.offer(a + "");
                // 如果队列满了,则跳出循环,结束添加
                if (!tag) {
                    break;
                }
                a = a + 1;
            }
        }
    }

    /**
     * @doWith 线程执行的任务:从队列中总共取出100000个元素
     * @date 2019年11月13日 上午10:28:26
     * @author Sir.Yang
     */
    @Override
    public void run() {
        while (true) {
            // 判断队列是否为空,为空则添加元素
            synchronized (QueueTest2.class) {
                if (queue.isEmpty()) {
                    putQueue();
                }
                if (list.size() < 1000000) {
                    // 消费数据,将数据存入集合
                    String string = queue.poll();
                    System.err.println(Thread.currentThread().getName() + ": " + string);
                    if (string != null && string != "") {
                        list.add(Integer.valueOf(string));
                    }
                } else {
                    break;
                }
            }
        }
    }
}
 

你可能感兴趣的:(Java,queue)