该栏目讲叙多线程基础、共享模型的内存、管程、无锁、不可变设计和多线程并发工具
不可变类的设计
设计原则
- final 的使用
- 属性用 final 修饰保证了该属性是只读的,不能修改
- 类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性
- 保护性拷贝:通过创建副本对象来避免共享问题(Arrays.copyOf())
- final 的使用
缺点
:由于保护性拷贝会产生大量副本,这样会增加内存的负担,可以关联享元模式思想设计
无状态类的设计
- :在设置类的时候不设置成员变量,这种没有任何成员变量的类是线程安全的,也是无状态的
享元模式
场景
:需要重用数量有限的同一类对象时连接池案例
/**
* 连接实体(不可变类)
*/
@Data
public final class Connection {
private final String name;
public Connection(String name) {
this.name = name;
}
}
/
/**
* 连接池
*/
public class ConnectionPool {
private final int capacity;
private final Connection[] connections;
private final AtomicIntegerArray status;
public ConnectionPool(int capacity) {
this.capacity = capacity;
this.connections = new Connection[capacity];
this.status = new AtomicIntegerArray(capacity);
for (int i = 0; i < capacity; i++) {
this.connections[i] = new Connection("连接" + i);
}
}
/**
* 获取连接对象
*
* @return 连接对象
*/
public Connection borrow() {
while (true) {
for (int i = 0; i < capacity; i++) {
if (status.get(i) == 0) {
if (status.compareAndSet(i, 0, 1)) {
return connections[i];
}
}
}
synchronized (this) {
try {
System.out.println("wait...");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 归还连接对象
*
* @param conn 连接对象
*/
public void free(Connection conn) {
for (int i = 0; i < capacity; i++) {
if (connections[i] == conn) {
status.set(i, 0);
synchronized (this) {
System.out.println("notify...");
this.notifyAll();
}
}
}
}
}
/
/**
* 测试类
*/
public class PoolDemo {
public static void main(String[] args) {
ConnectionPool pool = new ConnectionPool(2);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
final Connection conn = pool.borrow();
System.out.println("获取的连接对象:" + conn);
TimeUnit.SECONDS.sleep(2);
pool.free(conn);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}