My friend got this
question in an interview. Interviewer given two interfaces like below.
public interface Connection { /** * Return some integer. * * @return */ int read(); /** * Close the connection */ void close(); }
public interface ConnectionFactory { /* Return a connection object */ Connection getConnection(); }
Your implementation
should support following.
1.
Assume some
vendors have their own implementation of Connection and ConnectionFactory
interfaces. You need to provide pool of connections functionality to vendor’s
implementation.
2. If pool is empty, on first request new connection object should be added to pool. If all the
connection objects from pool are buzy, then you have to create new Connection
object and add to pool.
3.
If any
connection object is free in the pool, you can use.
4.
It should be
thread-safe
To solve this problem,
I want to use two collections, one to keep track of working connection objects
and other to keep tracking of free connection objects.
private
Set<Connection> workingPool = new HashSet<>();
private List<Connection> freePool = new ArrayList<>();
private List<Connection> freePool = new ArrayList<>();
I provided a constructor to ConnectionPool class to initialize Vendor specific connection factory.
public class ConnectionPool { private ConnectionFactory factory; public ConnectionPool(ConnectionFactory factory) { this.factory = factory; } }
One thing to be noted
is, whenever connection is closed, specific object should come back to the
freePool and wait for the next task. Let me implement this use case first.
private class ConnectionImpl implements Connection { private Connection conn; ConnectionImpl(Connection conn) { this.conn = conn; } @Override public int read() { return 0; } @Override public void close() { conn.close(); synchronized (obj) { workingPool.remove(this); freePool.add(this); } } }
ConnectionImpl(Connection
conn)
Above constructor is used to initialize vendor
specific Connection object.
As you observe close() method implementation, after
closing the connection, I removed it from workingPool and add it to freePool.
Now let me implement getConnection() method, As per
the requirement, if pool has any free connection objects, it should return,
else it should create new connection object and it should be thread safe. I
implemented getConnection method like below.
public Connection getConnection() { Connection conn = null; synchronized (obj) { if (freePool.isEmpty()) { conn = new ConnectionImpl(factory.getConnection()); workingPool.add(conn); return conn; } conn = freePool.remove(0); workingPool.add(conn); return conn; } }
Following is the
complete working application.
import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class ConnectionPool { private ConnectionFactory factory; private Set<Connection> workingPool = new HashSet<>(); private List<Connection> freePool = new ArrayList<>(); /* Dummy object to handle synchronization */ private Object obj = new Object(); public ConnectionPool(ConnectionFactory factory) { this.factory = factory; } public Connection getConnection() { Connection conn = null; synchronized (obj) { if (freePool.isEmpty()) { conn = new ConnectionImpl(factory.getConnection()); workingPool.add(conn); return conn; } conn = freePool.remove(0); workingPool.add(conn); return conn; } } private class ConnectionImpl implements Connection { private Connection conn; ConnectionImpl(Connection conn) { this.conn = conn; } @Override public int read() { return 0; } @Override public void close() { conn.close(); synchronized (obj) { workingPool.remove(this); freePool.add(this); } } } }
This is my view of
implementation, if you had any better suggestions, please comment your answer.
You may like
No comments:
Post a Comment