程序只在某些运行中陷入无限循环

时间:2016-06-29 12:36:16

标签: java multithreading concurrency queue

我正在研究并发运行的算法。它使用队列扩展平坦组合算法。问题是程序大部分时间运行正常,但每10次运行就会陷入无限循环。我尝试添加打印但是当我这样做时它不会进入无限循环。它循环多次以在调试模式下跟随它。 如果你能通过看到可能导致无限循环的场景来帮助我,我会非常感激。

package main;

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class MppRunner {

FlatCombiningQueue<Integer> queue;

enum Operation {
    ENQUEUE, DEQUEUE, NONE
};

public MppRunner(int num) {
    queue = new FlatCombiningQueue<Integer>(8);
}

public static void main(String[] args) throws Exception {

    MppRunner m = new MppRunner(8);
    Random rand = new Random();

    Thread[] thread = new Thread[8];
    AtomicInteger j = new AtomicInteger(0);
    AtomicInteger k = new AtomicInteger(0);
    AtomicInteger s = new AtomicInteger(0);
    for (int i = 0; i < 8; i++) {
        thread[i] = new Thread() {
            int i;

            public void run() {
                while ((i = j.getAndIncrement()) < 1000000) {
                    // System.out.printf("i is: %d\n", i);
                    if (rand.nextInt() % 2 == 0) {
                        try {
                            m.queue.enqueue(i);
                            k.getAndIncrement();
                        } catch (Exception e) {
                            System.out.println("boom");
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            if (m.queue.dequeue() != null)
                                s.getAndIncrement();
                        } catch (Exception e) {
                            System.out.println("boom");
                            e.printStackTrace();
                        }
                    }
                }
            }
        };
    }
    double start = System.currentTimeMillis();
    for (int i = 0; i < 8; i++)
        thread[i].start();
    for (int i = 0; i < 8; i++)
        thread[i].join();

    System.out.println("time = " + (System.currentTimeMillis() - start));

    while (m.queue.dequeue() != null)
        s.getAndIncrement();

    System.out.println(k + " = " + s);
}

public class FlatCombiningQueue<T> {

    volatile int numberOfThread;
    AtomicBoolean lock;
    AtomicReference<PublicationListNode> PublicationListHead;
    volatile QueueNode head;
    volatile QueueNode tail;
    volatile ArrayList1<PublicationListNode> localRecordArray;

    FlatCombiningQueue(int numberOfThread) {

        this.numberOfThread = numberOfThread;
        lock = new AtomicBoolean(false);
        PublicationListHead = new AtomicReference<PublicationListNode>(null);
        head = null;
        tail = null;
        localRecordArray = new ArrayList1<PublicationListNode>(
                numberOfThread);
    }

    public T dequeue() {

        int id = (int) Thread.currentThread().getId() % numberOfThread;
        if (localRecordArray.get(id) == null)
            createLocalNode(id);

        PublicationListNode temp = localRecordArray.get(id);
        temp.operation = Operation.DEQUEUE;
        localRecordArray.set(id, temp);

        if (lock.compareAndSet(false, true)) {
            // do {
            executeMethods();
            lock.set(false);

        } else
            while (localRecordArray.get(id).operation == Operation.DEQUEUE)
                ;

        return localRecordArray.get(id).value;
    }

    public void enqueue(T value) {

        int id = (int) Thread.currentThread().getId() % numberOfThread;
        if (localRecordArray.get(id) == null)
            createLocalNode(id);

        PublicationListNode temp = localRecordArray.get(id);
        temp.value = value;
        temp.operation = Operation.ENQUEUE;
        localRecordArray.set(id, temp);

        if (lock.compareAndSet(false, true)) {
            // do {
            executeMethods();
            lock.set(false);
            // } while (!PublicationListHead.get().first
            // && lock.compareAndSet(false, true));
        } else
            while (localRecordArray.get(id).operation == Operation.ENQUEUE)
                ;
    }

    public void createLocalNode(int id) {

        PublicationListNode newHead = new PublicationListNode();
        newHead.first = true;
        PublicationListNode oldHead;
        localRecordArray.set(id, newHead);
        do {
            oldHead = PublicationListHead.get();
            newHead.next = oldHead;
        } while (!PublicationListHead.compareAndSet(oldHead, newHead));
        if (oldHead != null)
            oldHead.first = false;
    }

    public void executeMethods() {

        PublicationListNode current = PublicationListHead.get();
        while (current != null) {
            if (current.operation == Operation.DEQUEUE)
                applyDequeue(current);
            else if (current.operation == Operation.ENQUEUE)
                applyEnqueue(current);

            current = current.next;
        }
    }

    private void applyDequeue(PublicationListNode current) {

        if (tail == null)
            current.value = null;
        else {
            current.value = tail.value;
            tail = tail.next;
            if (tail == null)
                head = null;
        }
        current.operation = Operation.NONE;
    }

    private void applyEnqueue(PublicationListNode current) {

        QueueNode node = new QueueNode(current.value);
        if (head != null) {
            head.next = node;
            head = head.next;
        } else {
            head = node;
            tail = head;
        }
        current.operation = Operation.NONE;
    }

    public class ArrayList1<E> {

        private E array[];

        @SuppressWarnings("unchecked")
        ArrayList1(int numberOfThread) {
            array = (E[]) new Object[numberOfThread];
        }

        public E get(int i) {
            return array[i];
        }

        public void set(int i, E value) {
            array[i] = value;
        }
    }

    public class PublicationListNode {

        volatile Boolean first;
        volatile Operation operation;
        volatile T value;
        PublicationListNode next;

        public PublicationListNode() {

            first = false;
            operation = Operation.NONE;
            value = null;
            next = null;
        }
    }

    public class QueueNode {

        volatile T value;
        volatile QueueNode next;

        QueueNode(T value) {
            this.value = value;
            next = null;
        }
    }
}

}

0 个答案:

没有答案