一、线程的状态及资源释放总结
线程状态分别为新建、就绪、运行、阻塞、死亡。new一个线程时状态为新建,调用start()方法状态变为就绪,当线程获得时间片时线程进入执行状态,调用线程的yield()方法则该线程立即放弃时间片重新进入就绪状态,如果线程持有锁不会释放锁。处于运行状态下的线程,调用对象的wait()方法则线程进入阻塞状态,直到其他线程调用对象的notify/notifyAll方法之后被唤醒进入就绪状态。注意,wait()方法会立即释放锁,而notify/notifyAll则不会立即释放锁,组要执行完代码块再释放所以在使用的时候最后好放在代码块的最后一行。线程的sleep方法会抛出中断异常,但是不会释放锁。当线程执行完run方法或者调用线程的stop方法线程会死亡,但是stop方法jdk不建议使用,因为该方法不会等待线程释放锁和资源有可能造成死锁和资源浪费。如果要中断程序,建议使用interrupt()方法。
wait()/notify/notifyAll方法会释放锁,但是释放的时间不同;sleep和yield不会释放锁。
二、手写连接池
为了方便实现实现java.sql的Connection接口来获取连接,只需重写creatStatement方法和commit方法,只是简单增加点延时来代表实际的业务操作。代码如下:
/*拿一个数据库连接*/
public static final Connection fetchConnection(){
return new SqlConnectionImpl();
}
@Override
public void commit() throws SQLException {
SleepTools.ms(70);
}
@Override
public Statement createStatement() throws SQLException {
SleepTools.ms(10);
return null;
}
接下来定义连接池,连接池的构造函数需要一个初始化大小,连接池支支持等待超时模式即在设定的时间内没有返回连接即认为超时。代码如下:
public class Pool {
private LinkedList<Connection> pool = new LinkedList<>();
public Pool(int initialSize) {
for (int i = 0; i < initialSize; i++) {
pool.addLast(SqlConnectionImpl.fetchConnection());
}
}
public Connection fetchConnection(long timeout) throws InterruptedException {
synchronized (pool) {
/*永不超时*/
if (timeout <= 0) {
while (pool.isEmpty()) {
pool.wait();
}
return pool.removeFirst();
} else {
/* 超时时间 */
long deadline = System.currentTimeMillis() + timeout;
long remain=timeout;
while (pool.isEmpty() && remain > 0) {
pool.wait(remain);
remain = deadline - System.currentTimeMillis();
}
Connection connection = null;
if (!pool.isEmpty()) {
connection = pool.removeFirst();
}
return connection;
}
}
}
public void releaseConnection(Connection connection) {
if (connection != null) {
synchronized (pool) {
pool.addLast(connection);
pool.notifyAll();
}
}
}
}
最后来测试这个连接池是否能够工作,启动50个线程,每个线程执行20次获取连接操作,统计超时的次数和未超时的次数。代码如下:
public class PoolTest {
static Pool pool = new Pool(10);
static CountDownLatch end;
static class Worker implements Runnable {
AtomicInteger get;
AtomicInteger notget;
int count;
public Worker(AtomicInteger get, AtomicInteger notget, int count) {
this.get = get;
this.notget = notget;
this.count = count;
}
@Override
public void run() {
while (count > 0) {
try {
Connection connection = pool.fetchConnection(1000);
if (connection != null) {
try {
connection.createStatement();
connection.commit();
} finally {
pool.releaseConnection(connection);
get.incrementAndGet();
}
} else {
notget.incrementAndGet();
System.out.println(Thread.currentThread().getName()
+ "等待超时!");
}
} catch (Exception e) {
} finally {
count--;
}
}
end.countDown();
}
}
public static void main(String[] args) throws InterruptedException {
int threadCount = 50; //启动的线程数
end = new CountDownLatch(threadCount);
int count = 20; //每个任务执行20次
AtomicInteger get = new AtomicInteger(); //成功获取链接
AtomicInteger notget = new AtomicInteger();//失败获取链接
for (int i = 0; i < threadCount; i++) {
new Thread(new Worker(get, notget, count), "work_" + i).start();
}
end.await();
System.out.println("请求执行的总次数: " + threadCount * count);
System.out.println("获取到链接的次数: " + get);
System.out.println("没有获取到链接的次数: " + notget);
}
}
执行结果:
......
work_22等待超时!
work_7等待超时!
work_41等待超时!
work_39等待超时!
work_25等待超时!
work_33等待超时!
请求执行的总次数: 1000
获取到链接的次数: 857
没有获取到链接的次数: 143