1 不可变设计
finall 的使用
- 属性用 finall 修饰保证了改属性是只读的,不能修改
- 类用finall修饰保证了改类中的方法不能被覆盖,防止子类无意间破坏不可变类
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
保护性拷贝
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
substring 会 new 一个新的字符串对象
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
Arrays.copyOfRange(value, offset, offset+count) 复制一份,不修改原有的字符数组
2 享元模式
2.1 定义
Flyweight pattern 当需要重用数量有限的同一类对象时
2.2 体现
2.2.1 包装类
在JDK中 Boolean、Byte、Short、Integer、Long、Character等包装类提供了 valueOf 方法,例如 Long 的 valueOf 会缓存 128~127 之间的 Long 对象,在这个范围之间会重用对象,大于这个范围,才会新建对象。
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
注意
- Byte,Short,Long 缓存的范围都是 -128 ~ 127
- Character 缓存的范围时 0 ~ 127
- Integer 的默认范围 -128 ~ 127,最小值不能变,但最大值可以通过调整虚拟机参数 -Djava.lang.Integer.IntegerCache.high 来改变
- Boolean缓存了 true 和 false
2.2.2 String 串池
2.2.3 BigDecimal BinInteger
3 自定义连接池
import lombok.extern.slf4j.Slf4j;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerArray;
@Slf4j
public class Demo {
public static void main(String[] args) {
Pool pool = new Pool(2);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
Connection connection = pool.getConnection();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.repaidConnection(connection);
}).start();
}
}
}
@Slf4j
class Pool {
/**
* 连接数
*/
static int size;
/**
* 连接数组
*/
static Connection[] connections;
/**
* 状态数组
*/
static AtomicIntegerArray status;
public Pool(int asize) {
size = asize;
connections = new Connection[size];
for (int i = 0; i < size; i++) {
connections[i] = new MockConnection("connection--" + i);
}
status = new AtomicIntegerArray(size);
log.info("连接池已创建,连接数:" + size);
}
/**
* 获取连接
*/
public Connection getConnection() {
// 循环整个连接数组 将状态为 0 的连接 返回
for (int i = 0; i < size; i++) {
if (status.get(i) == 0) {
while (true) {
if (status.compareAndSet(i, 0, 1)) {
log.info(Thread.currentThread().getName() + "获取连接" + connections[i]);
return connections[i];
}
}
}
}
// 没有状态为 0 的连接, 将当前线程进入阻塞队列
synchronized (this) {
try {
log.info(Thread.currentThread().getName() + "等待...");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return getConnection();
}
/**
* 归还连接
*/
public void repaidConnection(Connection connection) {
if (connection == null) {
throw new RuntimeException("该连接不对!");
}
for (int i = 0; i < size; i++) {
if (connection == connections[i]) {
while (true) {
if (status.compareAndSet(i, 1, 0)) {
log.info(Thread.currentThread().getName() + "归还连接" + connections[i]);
synchronized (this) {
this.notify();
}
return;
}
}
}
}
}
}
/**
* 模拟连接
*/
class MockConnection implements Connection {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MockConnection(String name) {
this.name = name;
}
@Override
public String toString() {
return "MockConnection{" +
"name='" + name + '\'' +
'}';
}
// ...
}
4 finall 原理
finall 变量的赋值 也会通过 putfield 指令来实现,同样在这条指令之后也会加入写屏障,保证在其它线程读到它的值时不会出现为 0 的情况
finall原理