diff --git a/src/main/java/xyz/zhouxy/plusone/commons/collection/LockedTable.java b/src/main/java/xyz/zhouxy/plusone/commons/collection/LockedTable.java
new file mode 100644
index 0000000..bc5a4b1
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/commons/collection/LockedTable.java
@@ -0,0 +1,276 @@
+package xyz.zhouxy.plusone.commons.collection;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Table;
+import xyz.zhouxy.plusone.commons.annotation.ReaderMethod;
+import xyz.zhouxy.plusone.commons.annotation.WriterMethod;
+
+import javax.annotation.concurrent.ThreadSafe;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * 使用 {@link ReentrantReadWriteLock} 将 {@link Table} 包装为线程安全的集合。
+ *
+ *
+ * 可通过以下方式构建一个线程安全的 {@link Table}
+ *
+ *
+ *
+ * LockedTable.of(HashBasedTable.create())
+ *
+ *
+ *
+ * NOTE: 如果 {@link Table} 不需要更改,请使用 {@link ImmutableTable}
+ *
+ *
+ * @author ZhouXY
+ * @see Table
+ * @see ImmutableTable
+ * @since 0.1.0-SNAPSHOT
+ */
+@Beta
+@ThreadSafe
+public class LockedTable implements Table {
+
+ private final Table table;
+
+ private final ReentrantReadWriteLock.ReadLock readLock;
+ private final ReentrantReadWriteLock.WriteLock writeLock;
+
+ private LockedTable(Table table, boolean fair) {
+ this.table = Objects.requireNonNull(table);
+ ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(fair);
+ this.readLock = rwl.readLock();
+ this.writeLock = rwl.writeLock();
+ }
+
+ public static LockedTable of(Table table) {
+ if (table instanceof LockedTable) {
+ return (LockedTable) table;
+ } else {
+ return new LockedTable<>(table, false);
+ }
+ }
+
+ public static LockedTable of(Table table, boolean fair) {
+ if (table instanceof LockedTable) {
+ return (LockedTable) table;
+ } else {
+ return new LockedTable<>(table, fair);
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public boolean contains(Object rowKey, Object columnKey) {
+ readLock.lock();
+ try {
+ return this.table.contains(rowKey, columnKey);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public boolean containsRow(Object rowKey) {
+ readLock.lock();
+ try {
+ return this.table.containsRow(rowKey);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public boolean containsColumn(Object columnKey) {
+ readLock.lock();
+ try {
+ return this.table.containsColumn(columnKey);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public boolean containsValue(Object value) {
+ readLock.lock();
+ try {
+ return this.table.containsValue(value);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public V get(Object rowKey, Object columnKey) {
+ readLock.lock();
+ try {
+ return this.table.get(rowKey, columnKey);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public boolean isEmpty() {
+ readLock.lock();
+ try {
+ return this.table.isEmpty();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public int size() {
+ readLock.lock();
+ try {
+ return this.table.size();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @WriterMethod
+ public void clear() {
+ writeLock.lock();
+ try {
+ this.table.clear();
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ @WriterMethod
+ public V put(R rowKey, C columnKey, V value) {
+ writeLock.lock();
+ try {
+ return this.table.put(rowKey, columnKey, value);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ @WriterMethod
+ public void putAll(Table extends R, ? extends C, ? extends V> table) {
+ writeLock.lock();
+ try {
+ this.table.putAll(table);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ @WriterMethod
+ public V remove(Object rowKey, Object columnKey) {
+ writeLock.lock();
+ try {
+ return this.table.remove(rowKey, columnKey);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Map row(R rowKey) {
+ readLock.lock();
+ try {
+ return this.table.row(rowKey);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Map column(C columnKey) {
+ readLock.lock();
+ try {
+ return this.table.column(columnKey);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Set> cellSet() {
+ readLock.lock();
+ try {
+ return this.table.cellSet();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Set rowKeySet() {
+ readLock.lock();
+ try {
+ return this.table.rowKeySet();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Set columnKeySet() {
+ readLock.lock();
+ try {
+ return this.table.columnKeySet();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Collection values() {
+ readLock.lock();
+ try {
+ return this.table.values();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Map> rowMap() {
+ readLock.lock();
+ try {
+ return this.table.rowMap();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @ReaderMethod
+ public Map> columnMap() {
+ readLock.lock();
+ try {
+ return this.table.columnMap();
+ } finally {
+ readLock.unlock();
+ }
+ }
+}
|