Java实现一个线程安全的循环单链表

有时候会有需要这样的场景,需要一个循环的链表做一些重复性的工作,比方说我们设计定时任务的时候,按照每一秒前进一个进行定时任务的读取,那么就需要有一个循环链表来做这样的数据结构,而java没有提供这样的一个数据结构,我在项目开发的时候也遇到了这样的问题,我们需要有管理定时任务,使用一个触发器来触发这些任务。

定义接口:

package com.algorithm.list;

/**
 * 循环链表接口定义
 *
 * @author riemann
 * @date 2019/07/13 23:52
 */
public interface CircularLinkedList<E> {

    /**
     * 向链表插入一个元素,默认在尾部
     * @param item
     */
    void add(E item);

    /**
     * 在链表的指定位置插入一个元素
     * @param index
     * @param item
     */
    void add(int index, E item);

    /**
     * 向链表插入一个元素,默认在尾部
     * @param item
     */
    void addLast(E item);

    /**
     * 向链表头部插入一个元素
     * @param item
     */
    void addFirst(E item);

    /**
     * 删除链表指针的当前位置的元素
     * @return
     */
    E remove();

    /**
     * 删除链表中的item元素
     * @param item
     */
    void remove(E item);

    /**
     * 删除链表中index位置的元素
     * @param index
     * @return
     */
    E remove(int index);

    /**
     * 删除链表头部元素
     * @return
     */
    E removeFirst();

    /**
     * 删除链表尾部元素
     * @return
     */
    E removeLast();

    /**
     * 移动链表当前位置指针到下一个位置
     */
    void next();

    /**
     * 返回链表的当前位置
     * @return
     */
    int currentIndex();

    /**
     * 返回链表当前位置元素
     * @return
     */
    E current();

    /**
     * 返回链表的头部元素
     * @return
     */
    E first();

    /**
     * 返回链表的尾部元素
     * @return
     */
    E last();

    /**
     * 获取链表index位置的元素
     * @param index
     * @return
     */
    E get(int index);

    /**
     * 清空链表
     */
    void clear();

    /**
     * 返回链表的长度
     * @return
     */
    int size();

    /**
     * 当前指针是否在头部
     * @return
     */
    boolean isFirst();

    /**
     * 当前指针是否在尾部
     * @return
     */
    boolean isLast();

    /**
     * 判断链表是否为空
     * @return
     */
    boolean isEmpty();

}

接下来就是实现类,我做了一个线程安全的实现。因为需要在多线程环境使用。这里使用了重入锁来保证线程安全。

package com.algorithm.list;

import java.util.Collection;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 实现一个线程安全的循环链表
 *
 * @author riemann
 * @date 2019/07/14 0:02
 */
public class ConcurrentCircularLinkedList<E> implements CircularLinkedList<E> {

    static class Node<E> {
        E item;
        Node<E> next;
        Node(E item) {
            this.item = item;
        }
    }

    final ReentrantLock lock = new ReentrantLock();

    private Node<E> first;

    private Node<E> last;

    private Node<E> current;

    private int currentIndex;

    private int count = 0;

    private int capacity;

    public ConcurrentCircularLinkedList() {
        this(Integer.MAX_VALUE);
    }

    public ConcurrentCircularLinkedList(int capacity) {
        this.capacity = capacity;
        current = first = last = new Node<E>(null);
        currentIndex = -1;
    }

    public ConcurrentCircularLinkedList(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        for (E item : c) {
            addLast(item);
        }
    }

    private Node<E> getNode(int index) {
        if(index < 0 || index > size()) {
            throw new ArrayIndexOutOfBoundsException();
        }
        Node<E> node = first;
        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        return node;
    }

    @Override
    public void add(E item) {
        addLast(item);
    }

    @Override
    public void add(int index, E item) {
        lock.lock();
        if (index < 0 || index > size()) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if (count >= capacity) {
            throw new IllegalArgumentException();
        }
        try {
            Node<E> node = new Node<E>(item);
            // 链表为null时,first,last,current都指向第一个元素
            if (this.isEmpty()) {
                first = node;
                last = node;
                current = first;
                last.next = first;
                currentIndex = 0;
            } else {
                // 头部插入的时候
                if (index == 0) {
                    node.next = first;
                    first = node;
                    last.next = node;
                } else if (index == size()) { // 尾部插入
                    last.next = node;
                    last = node;
                    node.next = first;
                } else {
                    Node<E> n = this.first;
                    for (int i = 0; i < index; i++) {
                        n = n.next;
                    }
                    node.next = n.next;
                    n.next = node;
                }
                if (index <= this.currentIndex) {
                    this.currentIndex ++;
                }
            }
            count++;
        } finally {
            lock.unlock();
        }

    }

    @Override
    public void addLast(E item) {
        if (count == 0) {
            add(0, item);
        } else {
            add(count, item);
        }
    }

    @Override
    public void addFirst(E item) {
        add(0, item);
    }

    @Override
    public E remove() {
        return remove(currentIndex);
    }

    @Override
    public void remove(E item) {
        lock.lock();
        try {
            Node<E> n = this.first;
            for (int i = 0; i < size(); i++) {
                if (n.item.equals(item)) {
                    remove(i);
                    break;
                }
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    public E remove(int index) {
        E item = null;
        lock.lock();
        try {
            if(index < 0 || index > size()){
                throw new ArrayIndexOutOfBoundsException();
            }
            if(count == 0){
                throw new IllegalArgumentException();
            }
            // 链表里面只剩下一个元素了
            if (first.next == first) {
                current = first = last = new Node<E>(null);
                currentIndex = -1;
            } else {
                // 删除头部
                if (index == 0) {
                    item = first.item;
                    if (current == first) {
                        current = first.next;
                    }
                    Node<E> node = first;
                    first = first.next;
                    last.next = first;
                    node.next = null;
                } else if (index == (size() - 1)) {// 删除尾部
                    item = last.item;
                    Node<E> pre = getNode(index - 1);
                    if (current == last) {
                        current = pre;
                        currentIndex--;
                    }
                    pre.next = first;
                    last.next = null;
                    last = pre;
                } else {
                    Node<E> pre = getNode(index - 1);
                    Node<E> node = pre.next;
                    item = node.item;
                    if (node == current) {
                        current = node.next;
                    }
                    pre.next = node.next;
                    node.next = null;
                    if (index <= currentIndex) {
                        currentIndex--;
                    }
                }
            }
            count--;
        } finally {
            lock.unlock();
        }
        return item;
    }

    @Override
    public E removeFirst() {
        return remove(0);
    }

    @Override
    public E removeLast() {
        return remove(size() - 1);
    }

    @Override
    public void next() {
        lock.lock();
        try {
            current = current.next;
            currentIndex++;
            if (current == first) {
                currentIndex = 0;
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    public int currentIndex() {
        return this.currentIndex;
    }

    @Override
    public E current() {
        return get(currentIndex);
    }

    @Override
    public E first() {
        return first.item;
    }

    @Override
    public E last() {
        return last.item;
    }

    @Override
    public E get(int index) {
        return null;
    }

    @Override
    public void clear() {

    }

    @Override
    public int size() {
        return count;
    }

    @Override
    public boolean isFirst() {
        return this.currentIndex == 0;
    }

    @Override
    public boolean isLast() {
        return this.currentIndex == (size() - 1);
    }

    @Override
    public boolean isEmpty() {
        return count == 0;
    }

    public String toString() {
        if (isEmpty()) {
            return "[]";
        }
        StringBuffer buffer = new StringBuffer();
        buffer.append("[");
        Node<E> node = first;
        while (true) {
            buffer.append(node.item);
            node = node.next;
            if (node.next == first) {
                if (node != first) {
                    buffer.append(node.item);
                    buffer.append(",");
                }
                buffer.append("");
                break;
            }
        }
        buffer.append("]");
        return buffer.toString();
    }

}

然后做一个简单的算法例子来验证功能的可用性,

100个人围成圆圈,从1开始报数,喊道3人的时候退出,重复。直到剩下最后一个人。

package com.algorithm.list;

import org.junit.Test;

/**
 * @author riemann
 * @date 2019/07/14 1:24
 */
public class CircularLinkedListTest {

    @Test
    public void test() {
        CircularLinkedList<String> list = new ConcurrentCircularLinkedList<String>();
        for (int i = 1; i < 101; i++) {
            list.add("" + i);
        }
        int count = 1;
        while (list.size() > 1) {
            list.next();
            count++;
            if (count % 3 == 0) {
                System.out.println(list.remove() + " break!");
                count++;
            }
        }
        System.out.println(list.toString());
    }

}

输出结果:

3 break!
5 break!
7 break!
9 break!
11 break!
13 break!
15 break!
17 break!
19 break!
21 break!
23 break!
25 break!
27 break!
29 break!
31 break!
33 break!
35 break!
37 break!
39 break!
41 break!
43 break!
45 break!
47 break!
49 break!
51 break!
53 break!
55 break!
57 break!
59 break!
61 break!
63 break!
65 break!
67 break!
69 break!
71 break!
73 break!
75 break!
77 break!
79 break!
81 break!
83 break!
85 break!
87 break!
89 break!
91 break!
93 break!
95 break!
97 break!
99 break!
2 break!
6 break!
10 break!
14 break!
18 break!
22 break!
26 break!
30 break!
34 break!
38 break!
42 break!
46 break!
50 break!
54 break!
58 break!
62 break!
66 break!
70 break!
74 break!
78 break!
82 break!
86 break!
90 break!
94 break!
98 break!
4 break!
12 break!
20 break!
28 break!
36 break!
44 break!
52 break!
60 break!
68 break!
76 break!
84 break!
92 break!
1 break!
24 break!
40 break!
56 break!
72 break!
88 break!
8 break!
48 break!
80 break!
16 break!
96 break!
64 break!
100 break!
[32]

代码详情在我的github仓库下:
https://github.com/riemannChow/LeetCode/tree/master/src/main/java/com/algorithm/list

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老周聊架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值