diff --git a/src/main/java/xyz/zhouxy/plusone/commons/collection/SynchronizedTable.java b/src/main/java/xyz/zhouxy/plusone/commons/collection/SynchronizedTable.java new file mode 100644 index 0000000..d1f8811 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/collection/SynchronizedTable.java @@ -0,0 +1,205 @@ +package xyz.zhouxy.plusone.commons.collection; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import javax.annotation.concurrent.ThreadSafe; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Table; + +/** + * 将 {@link Table} 包装为同步集合,线程安全。 + * + *

+ * 可通过以下方式构建一个线程安全的 {@link Table} + *

+ * + *
+ * new SynchronizedTable<>(HashBasedTable.create())
+ * 
+ * + *

+ * NOTE: 如果 {@link Table} 不需要更改,请使用 {@link ImmutableTable} + *

+ * + * @author ZhouXY + * @since 0.1.0-SNAPSHOT + * @see Table + * @see ImmutableTable + */ +@Beta +@ThreadSafe +public class SynchronizedTable implements Table, Serializable { + + private static final long serialVersionUID = 3716653837549439569L; + + @SuppressWarnings("serial") + private final Table table; + @SuppressWarnings("serial") + private final Object mutex; + + private SynchronizedTable(Table table) { + this.table = Objects.requireNonNull(table); + this.mutex = this; + } + + private SynchronizedTable(Table table, Object mutex) { + this.table = Objects.requireNonNull(table); + this.mutex = mutex; + } + + public static SynchronizedTable of(Table table) { + if (table instanceof SynchronizedTable) { + return (SynchronizedTable) table; + } else { + return new SynchronizedTable<>(table); + } + } + + public static SynchronizedTable of(Table table, Object mutex) { + if (table instanceof SynchronizedTable) { + SynchronizedTable srcTable = (SynchronizedTable) table; + return new SynchronizedTable<>(srcTable.table, mutex); + } else { + return new SynchronizedTable<>(table); + } + } + + @Override + public boolean contains(Object rowKey, Object columnKey) { + synchronized (mutex) { + return this.table.contains(rowKey, columnKey); + } + } + + @Override + public boolean containsRow(Object rowKey) { + synchronized (mutex) { + return this.table.containsRow(rowKey); + } + } + + @Override + public boolean containsColumn(Object columnKey) { + synchronized (mutex) { + return this.table.containsColumn(columnKey); + } + } + + @Override + public boolean containsValue(Object value) { + synchronized (mutex) { + return this.table.containsValue(value); + } + } + + @Override + public V get(Object rowKey, Object columnKey) { + synchronized (mutex) { + return this.table.get(rowKey, columnKey); + } + } + + @Override + public boolean isEmpty() { + synchronized (mutex) { + return this.table.isEmpty(); + } + } + + @Override + public int size() { + synchronized (mutex) { + return this.table.size(); + } + } + + @Override + public void clear() { + synchronized (mutex) { + this.table.clear(); + } + } + + @Override + public V put(R rowKey, C columnKey, V value) { + synchronized (mutex) { + return this.table.put(rowKey, columnKey, value); + } + } + + @Override + public void putAll(Table table) { + synchronized (mutex) { + this.table.putAll(table); + } + } + + @Override + public V remove(Object rowKey, Object columnKey) { + synchronized (mutex) { + return this.table.remove(rowKey, columnKey); + } + } + + @Override + public Map row(R rowKey) { + synchronized (mutex) { + return this.table.row(rowKey); + } + } + + @Override + public Map column(C columnKey) { + synchronized (mutex) { + return this.table.column(columnKey); + } + } + + @Override + public Set> cellSet() { + synchronized (mutex) { + return this.table.cellSet(); + } + } + + @Override + public Set rowKeySet() { + synchronized (mutex) { + return this.table.rowKeySet(); + } + } + + @Override + public Set columnKeySet() { + synchronized (mutex) { + return this.table.columnKeySet(); + } + } + + @Override + public Collection values() { + synchronized (mutex) { + return this.table.values(); + } + } + + @Override + public Map> rowMap() { + synchronized (mutex) { + return this.table.rowMap(); + } + } + + @Override + public Map> columnMap() { + synchronized (mutex) { + return this.table.columnMap(); + } + } +}