How to synchronize two methods in a singleton pattern - java

I have created a database object according to the singleton pattern. The database object contains 2 methods: connect() and update().
The update should run multithreaded, meaning that I cannot put synchronized in the update method signature (I want users to access it simultaneously not one at a time).
My problem is that I want to make sure that 2 scenarios according to this flows:
A thread 1 (user1) is the first to create an instance of the DB and thread 2 (user2) is calling the connect() and update() method to this DB - should not give NullPointerException even if by the time that user2 is doing the update() the connect from user1 is not done.
update() should not include synchronized (because of the reason I mentioned above).
Thanks for all the helpers!
SingeltonDB
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SingeltonDB {
private static DBconnImpl db = null;
private static SingeltonDB singalDb = null;
Lock dbLock;
private SingeltonDB(String username, String password) {
db = new DBconnImpl();
}
public static boolean isOpen() {
return (db != null);
}
public synchronized static SingeltonDB getInstance(String username,
String password) throws Exception {
if (db != null) {
throw (new Exception("The database is open"));
} else {
System.out.println("The database is now open");
singalDb = new SingeltonDB(username, password);
}
db.connect(username, password);
System.out.println("The database was connected");
return singalDb;
}
public synchronized static SingeltonDB getInstance() throws Exception {
if (db == null) {
throw (new Exception("The database is not open"));
}
return singalDb;
}
public void create(String tableName) throws Exception {
dbLock = new ReentrantLock();
dbLock.lock();
db.create(tableName);
dbLock.unlock();
}
public User query(String tableName, int rowID) throws Exception {
if (db == null) {
System.out.println("Error: the database is not open");
return null;
}
return (db.query(tableName, rowID));
}
public void update(String tableName, User user) throws Exception {
if (db == null) {
System.out.println("Error: the database is not open");
return;
}
db.update(tableName, user);
}
}
Main
public class Main {
public static void main(String[] args) throws Exception {
Creator cr= new Creator(new UserContorller());
Thread t1 = new Thread(cr);
t1.start();
Producer pr = new Producer(new UserContorller());
Thread t2 = new Thread(pr);
t2.start();
/*
* Consumer cn = new Consumer(new UserContorller()); Thread t2 = new
* Thread(cn); t2.start();
*/
}
}
class Creator implements Runnable {
UserContorller uc;
public Creator(UserContorller uc) {
this.uc = uc;
}
#Override
public void run() {
try {
uc = new UserContorller("MyAccount", "123");
uc.createTable("table1");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Producer implements Runnable {
UserContorller uc;
public Producer(UserContorller uc) {
this.uc = uc;
}
#Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
uc.saveUser("table1", i, "User", i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
UserContorller uc;
public Consumer(UserContorller uc) {
this.uc = uc;
}
#Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
System.out.println(uc.getUser("table1", i));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

Note: The post below was written in the perspective of both users using the same credentials (hidden from them) to connect to the database. If users employ different credentials, the idea of a singleton db object is purposeless, each user should have their own connection object, and of course then connection details are passed on from the user to the Db via whatever represents the user in the program (here the thread instances apparently).
The main issue in the implementation you provided is that the getinstance method requires its caller to know the connection details, or assume that the connection has already been done. But neither threads could nor should know in advance if the Db has been opened already -- and design wise it's a mistake to hand them the responsibility of explicitely opening it. These threads are work threads, they shouldn't be concerned about Db configuration details.
The only sane way to handle this situation is to have these configuration parameters held by the Db object directly, or better yet another object in charge of providing it (it's the factory pattern).
However, if you want first your code to work with minimal changes, get rid of the parameter less getinstance method, have any thread requiring the Db object to use the remaining variant of that method, passing along the correct parameters, and change it to return the instance if it exists, or create it otherwise, without raising an exception. I believe that it's what #Dima has been trying to explain in his answer.

Connect once, when creating the singleton (in the constructor, perhaps).
Have a synchronized static method (getInstance or something), that checks if an instance exists, creates and connects as necessary, and returns the instance. By following this protocol, you ensure that threads always get a connected Db object ready to be used.
The users will call that method to get the singleton instance, and call update or whatever they want on it, it does not need to be synchronized.

Related

Why Class.forName() in static code terminate the process when using mutil-thread? [duplicate]

This question already has answers here:
JUnit terminates child threads
(6 answers)
Closed 2 years ago.
I'm currently learning JDBC. And I try to update the product information and insert a log at the same time.
private void testTransaction() {
try {
// Get Connection
Connection connection = ConnectionUtils.getConnection();
connection.setAutoCommit(false);
// Execute SQL
Product product = new Product(1, 4000d);
productService.updateProduct(connection, product);
Log log = new Log(true, "None");
logService.insertLog(connection, log);
// Commit transaction
connection.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
ConnectionUtils.closeConnection();
}
}
When using single thread, it would be fine.
#Test
public void testMultiThread() {
testTransaction();
}
But When I using multi-thread, even start one thread, the process would terminate automatically.
#Test
public void testMultiThread() {
for (int i = 0; i < 1; i++) {
new Thread(this::testTransaction).start();
}
}
After debugging, I found that it was Class.forName() function in ConnectionUtils cause this situation.
public class ConnectionUtils {
static private String url;
static private String driver;
static private String username;
static private String password;
private static Connection connection = null;
private static ThreadLocal<Connection> t = new ThreadLocal<>();
static {
try {
Properties properties = new Properties();
properties.load(new FileReader("src/main/resources/jdbcConnection.properties"));
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
connection = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
} finally {
t.set(connection);
}
return connection;
}
}
The process will terminate at Class.forName(). I found this by adding two print funcion before and after the statement. And only the former works.
System.out.println("Before");
Class.forName(driver);
System.out.println("After");
The console only print the Before and doesn't show any exception information.
I want to know that why multi-thread in java will cause this situation and how to solve this problem.
This is more likely your test method complete before your other threads and the test framework is not waiting (junit?). You need to wait until the threads have completed. You should use an Executors, this is more convinient.
#Test
public void testMultiThread() {
Thread[] threads = new Thread[1];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(this::testTransaction);
threads[i].start();
}
// wait thread completion
for (Thread th : threads) {
th.join();
}
}
Junit will terminate all your thread as long as the test method finish.
In your case, test will finish when the loop ends, it doesn't care whether
testTransaction has finished. It has nothing to do with class.forName , maybe it's just because this method exceute longer.
you can check this answer

Threaded TCP server-trying to maintain data consistency of a User Repository

So I have a TCP server which has the ability for clients to register users.It contains a UserRepo object which holds the registered users and handles the adding of users.How do I make it that even with multiple clients accessing my server on different threads that the data for UserRepo remains consistent and correct across all threads?
Server.java
package danielhaughtonemailapplicationca1;
import java.io.*;
import java.net.*;
class Server implements Runnable
{
Socket connectionSocket;
UserRepo userRepo;
public Server(Socket s){
try{
System.out.println("Client Got Connected " );
connectionSocket=s;
userRepo = new UserRepo();
}catch(Exception e){e.printStackTrace();}
}
public void run(){
try{
User loggedInUser = null;
String input="";
while(!"exit".equals(input)){
BufferedReader reader =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
BufferedWriter writer=
new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()));
if(loggedInUser == null){
loginOrRegister(reader,writer,input);
}else{
}
}
System.out.println("A connection was closed");
connectionSocket.close();
}catch(Exception e){e.printStackTrace();}
}
public void loginOrRegister(BufferedReader reader,BufferedWriter writer,String input) throws IOException{
while(input.equals("exit")){
writer.write("*** Hi!Write login to login or register to register ***\r\n");
writer.flush();
input = reader.readLine().trim();
if(input.equals("register")){
writer.write("*** write the email address you want ***\r\n");
writer.flush();
String email = reader.readLine().trim();
writer.write("*** write the password you want ***\r\n");
writer.flush();
String password = reader.readLine().trim();
User user = userRepo.addUser(email, password);
}else if(input.equals("login")){
}
}
}
public static void main(String argv[]) throws Exception
{
System.out.println("Threaded Server is Running " );
ServerSocket mysocket = new ServerSocket(5555);
while(true)
{
Socket sock = mysocket.accept();
Server server=new Server(sock);
Thread serverThread=new Thread(server);
serverThread.start();
}
}
}
UserRepo
public class UserRepo {
ArrayList<User> registeredUsers;
public UserRepo() {
}
public UserRepo(ArrayList<User> registeredUsers) {
this.registeredUsers = registeredUsers;
}
public ArrayList<User> getRegisteredUsers() {
return registeredUsers;
}
public void setRegisteredUsers(ArrayList<User> registeredUsers) {
this.registeredUsers = registeredUsers;
}
public User addUser(String email,String password){
for(int i=0;i<=registeredUsers.size();i++){
if(registeredUsers.get(i).getEmail().equalsIgnoreCase("email")){
//if the email already exists,return null,we cant add the user
return null;
}
}
//if we get here the user can be added
User user = new User(email,password);
registeredUsers.add(user);
return user;
}
public User login(String email,String password){
for(int i=0;i<=registeredUsers.size();i++){
if(registeredUsers.get(i).getEmail().equalsIgnoreCase("email")){
//here we found the user with the given email
//lets check if the password is right
if(password.equals(registeredUsers.get(i).getPassword())){
//password is right
return registeredUsers.get(i);
}else{
//the password isnt correct
return null;
}
}
}
//we get here if we didnt find a matching email,return null
return null;
}
}
Probably the most basic synchronization mechanism in Java is the use of synchronized, either as a method modifier [1] (i.e. public synchronized User addUser(String email,String password) or as a statement [2].
Of course, the smaller the synchronized block (whether as a statement or as a function), the less performance you have to trade since other threads will block (be waiting) for a smaller number of instructions.
In this case, you could do something like:
synchronized(this) {
registeredUsers.add(user);
}
This would make Thread A acquire a lock on the registeredUsers. When Thread B tries to add a new user while another is being added, Thread B would wait until it can acquire the lock from Thread A (in this case, as soon as Thread A's execution leaves the synchronized block).
See also the references below.
[1] https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
[2] https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Java Threading - Wait for data to be returned, but don't block other threads

I have 7 threads running in an ExecutorPool that process data and occasionally need data from a listener instance running on another thread. The listener sends a request over a socket to a server and a while later, when the result is returned, the listener will return the data to the worker thread that called it. I want to block the worker thread until the requested data is returned, but I don't want to block the listener from making other requests from the other worker threads. How do I do that?
If one thread hands off work to another thread, and then subsequently simply waits for the result, you don't need another thread to do the work. You may need a class that does the work, but which is called on the same thread. And if the same instance is used by multiple threads some synchronization may be needed. But the bottom line is this :
You don't need the listener thread. Replace it with a component that handles a request, and call it synchronously.
Edit
Given your own answer, your problem is a bit clearer. As #JimN suggests you probably want to hand out a Future to the worker thread, and make it a CompletableFuture the Listener keeps in a Map keyed by request id until the response returns.
Sample code :
public class WorkUnitProcessor implements Runnable {
// ...
#Override
public void run() {
while(true) {
WorkUnit work = master.getNextWorkUnit();
if(work == null) return;
doWork(work);
}
}
public void doWork(WorkUnit work) {
//Do some work...
try {
DataRequest dataRequest = createRequest(work);
Future<Response> future = server.getData(dataRequest);
Response response = future.get(); // this call blocks until the Response is available.
//finish doing work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
// handle e.getCause()
}
}
// ...
}
public class Server implements DataSourceDrivenCallback {
private final DataSource dataSource;
private Map<Integer, CompletableFuture<Response>> openRequests = new ConcurrentHashMap<>();
public Server(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public void incomingDataCallback(int requestId, ChunkOfData requestedData) {
CompletableFuture<Response> responseHolder = openRequests.remove(requestId); // get the responseHolder
if (responseHolder != null) {
responseHolder.complete(toResponse(requestedData)); // make the response available.
}
}
public Future<Response> getData(DataRequest datarequest) {
int requestId = dataSource.submitRequest(serializeAndTranslateRequest(datarequest));
CompletableFuture<Response> future = new CompletableFuture<>();
openRequests.put(requestId, future);
return future;
}
// ...
}
I think this might work. What I was looking for is described here:
https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
It's the ability to make a thread sleep until it is notified by the thread that it is waiting on. Seems easy to use.
public class DataProcessor {
private List<WorkUnit> work;
private Server server;
public DataProcessor(List<WorkUnit> work, int numprocessors) {
this.work = work;
setupProcessors(numprocessors);
Server server = new Server();
}
private void setupProcessors(int numprocessors) {
for(int i = 0; i < numprocessors; i++) {
WorkUnitProcessor worker = new WorkUnitProcessor(this, server);
worker.start();
}
}
public synchronized WorkUnit getNextWorkUnit() {
if(work.isEmpty()) return null;
return work.remove(0);
}
}
public class WorkUnitProcessor(Server server) {
private DataProcessor master;
private Server server;
public WorkUnitProcessor(DataProcessor master) {
this.master = master;
}
#Override
public void run() {
while(true) {
WorkUnit work = master.getNextWorkUnit();
if(work == null) return;
doWork(work);
}
}
public void doWork(WorkUnit work) {
//Do some work...
server.getData(datarequest, this);
while(!datarequest.filled) {
try {
wait();
} catch (InterruptedException e) {}
}
//finish doing work
}
}
public class Server implements DataSourceDrivenCallback {
private DataSource ds;
private Map<Integer, OpenRequest> openrequests;
public Server() {
//setup socket and establish communication with server through DataSource object
DataSource ds = new DataSource(<ID>, <Socket>);
}
public synchronized void getData(DataRequest datarequest, WorkUnitProcessor workerthread) {
int requestid = ds.submitRequest(serializeAndTranslateRequest(datarequest));
openrequests.add(new OpenRequest(workerthread, datarequest));
}
#Override
public void incomingDataCallback(int requestid, ChunkOfData requesteddata) {
OpenRequest request = openrequests.get(requestid);
request.datarequest.storeData(requesteddata);
request.workerthread.notify();
}
}
public class OpenRequest {
private WorkUnitProcessor workerthread;
private DataRequest datarequest;
//other details about request
}

Java: Concurency with HikariDataSource Object

I have a class which looks like that:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class ConnectionPool {
private HikariDataSource hds;
private final String propertyFileName;
public ConnectionPool(String propertyFileName) {
if (propertyFileName == null) {
throw new IllegalArgumentException("propertyFileName can't be null");
}
this.propertyFileName = propertyFileName;
reloadFile();
}
public void reloadFile() {
if (hds != null) {
hds.close();
}
hds = new HikariDataSource(new HikariConfig(propertyFileName));
}
public HikariDataSource getHikariDataSource() {
return hds;
}
public String getPropertyFileName() {
return propertyFileName;
}
public void executeQuery(final String sql, final CallBack<ResultSet, SQLException> callBack) {
new Thread(new Runnable() {
#Override
public void run() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = hds.getConnection();
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
callBack.call(resultSet, null);
} catch (SQLException e) {
callBack.call(null, e);
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException ignored) {}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException ignored) {}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException ignored) {}
}
}
}
}).start();
}
public void executeUpdate(final String sql, final CallBack<Integer, SQLException> callBack) {
//TODO
}
public void execute(final String sql, final CallBack<Boolean, SQLException> callBack) {
//TODO
}
public void connection(final String sql, final CallBack<Connection, SQLException> callBack) {
//TODO
}
}
The problem is that the reloadFile() method can be called from a different thread as hds is used. So it's possible that hds is closed while I use a connection object of it in another thread. What's the best way to solve this problem? Should I wait a few seconds after creating the new HikariDataSource object befor closing the old one (until the queries are finished)?
Edit: Another question: Should hds be volatile, so that the changes of hds are visible for all threads?
Have had a very very quick and brief look in the source code in HikariDataSource. In its close(), it is calling its internal HikariPool's shutdown() method, for which it will try to properly close the pooled connections.
If you want to even avoid any chance that in-progress connection from force closing, one way is to make use of a ReadWriteLock:
public class ConnectionPool {
private HikariDataSource hds;
private ReentrantReadWriteLock dsLock = ....;
//....
public void reloadFile() {
dsLock.writeLock().lock();
try {
if (hds != null) {
hds.close();
}
hds = new HikariDataSource(new HikariConfig(propertyFileName));
} finally {
dsLock.writeLock().unlock();
}
}
public void executeQuery(final String sql, final CallBack<ResultSet, SQLException> callBack) {
new Thread(new Runnable() {
#Override
public void run() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
dsLock.readLock().lock();
try {
connection = hds.getConnection();
// ....
} catch (SQLException e) {
callBack.call(null, e);
} finally {
// your other cleanups
dsLock.readLock().unlock();
}
}
}).start();
}
//....
}
This will make sure that
multiple thread can access your datasource (to get connection etc)
Reload of datasource needs to wait until thread using the datasource to complete
No thread is able to use the datasource to get connection when it is reloading.
Why exactly are you trying to cause HikariCP to reload? Many of the important pool parameters (minimumIdle,maximumPoolSize,connectionTimeout,etc.) are controllable at runtime through the JMX bean without restarting the pool.
Restarting the pool is a good way to "hang" your application for several seconds while connections are closed and rebuilt. If you can't do what you need through the JMX interface, Adrian's suggestion seems like quite a reasonable solution.
Other solutions are possible, but have more complexity.
EDIT: Just for my own entertainment, here is the more complex solution...
public class ConnectionPool {
private AtomicReference<HikariDataSource> hds;
public ConnectionPool(String propertyFileName) {
hds = new AtomicReference<>();
...
}
public void reloadFile() {
final HikariDataSource ds = hds.getAndSet(new HikariDataSource(new HikariConfig(propertyFileName)));
if (ds != null) {
new Thread(new Runnable() {
public void run() {
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + ds.getPoolName() + ")");
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class);
poolProxy.softEvictConnections();
do {
Thread.sleep(500);
} while (poolProxy.getActiveConnections() > 0);
ds.close();
}
}).start();
}
}
public HikariDataSource getHikariDataSource() {
return hds.get();
}
public void executeQuery(final String sql, final CallBack<ResultSet, SQLException> callBack) {
new Thread(new Runnable() {
#Override
public void run() {
...
try {
connection = getHikariDataSource().getConnection();
...
}
}
}).start();
}
}
This will swap out the pool (atomically) and will start a thread that waits until all active connections have returned before shutting down the orphaned pool instance.
This assumes that you let HikariCP generate unique pool names, i.e. do not set poolName in your properties, and that registerMbeans=true.
A few options:
Synchronize all access to the data source so that only one thread can ever be messing with it. Not scaleable, but workable.
Roll your own connection pooling, such as Apache Commons Pooling so that each access, regardless of thread, requests a data source and pooling creates one as necessary. Can mess with data ACID, just depends on whether dirty data is needed, when data is flushed, transactionality, etc.
Each thread could also have its own data source using ThreadLocal so that each thread is totally independent of each other. Again, quality of data might be an issue, resources might be an issue if you've got "lots" of threads (depends on your definition) and too many open connections cause resource issues on either the client or server.

making sure one task completes before another starts in java

Can anyone show me a way to force one task in java to complete before the next task is allows to start? Specifically, I want to edit the code below so that the first marked two lines of code are completely finished before the next marked two lines are called.
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String idString = req.getParameter("id");
Long id = new Long(idString);
//complete the actions specified on next two lines
School school = new SchoolDAO().findSchool(id);
req.setAttribute("school", school);
//before even starting the actions specified on the next two lines
List<CourseSummary> coursesummaries = new CourseSummaryDAO().findAllcsum(id);
req.setAttribute("coursesummaries", coursesummaries);
jsp.forward(req, resp);
}
EDIT:
To better understand Fernando's suggestion, I am including some relevant parts of SchoolDAO as follows:
public class SchoolDAO extends DataAccessObject{
public School findSchool(Long id) {
ResultSet rs = null;
PreparedStatement statement = null;
Connection connection = null;
try {
connection = getConnection();
String sql = "select * from schoolprog where id=?";
statement = connection.prepareStatement(sql);
statement.setLong(1, id.longValue());
rs = statement.executeQuery();
if (!rs.next()) {return null;}
return readSchool(rs);
}
catch (SQLException e) {throw new RuntimeException(e);}
finally {close(rs, statement, connection);}
}
private School readSchool(ResultSet rs) throws SQLException {
Long id = new Long(rs.getLong("id"));
String spname = rs.getString("spname");
String spurl = rs.getString("spurl");
School school = new School();
school.setId(id);
school.setName(spname);
school.setUrl(spurl);
return school;
}
}
Similarly, CourseSummaryDAO contains:
public class CourseSummaryDAO extends DataAccessObject{
public List<CourseSummary> findAllcsum(Long sid) {
LinkedList<CourseSummary> coursesummaries = new LinkedList<CourseSummary>();
ResultSet rs = null;
PreparedStatement statement = null;
Connection connection = null;
try {
connection = getConnection(); //this is the line throwing null pointer error
String sql = "select * from coursetotals where spid=?";
statement = connection.prepareStatement(sql);
statement.setLong(1, sid);
rs = statement.executeQuery();
//for every row, call read method to extract column
//values and place them in a coursesummary instance
while (rs.next()) {
CourseSummary coursesummary = readcsum("findAll", rs);
coursesummaries.add(coursesummary);
}
return coursesummaries;
}
catch (SQLException e) {throw new RuntimeException(e);}
finally {close(rs, statement, connection);}
}
The line where the program is breaking is:
connection = getConnection(); //
If you have two tasks that should be performed serially (i.e. one finishes before the next one starts) then the best answer is to perform them synchronously. For instance, suppose that task1() and task2() are the tasks:
// Wrong way:
Runnable r1 = new Runnable(){
public void run() {
task1();
}};
Runnable r2 = new Runnable(){
public void run() {
// Wait for r1 to finish task1 ... somehow
task2();
}};
// Right way:
Runnable r = new Runnable(){
public void run() {
task1();
task2();
}};
And in your case, it looks like the doGet call can only return when it gets the result of both tasks. So that suggests that you shouldn't be using threads at all in this case. Just call task1() and task2() in sequence ... on the request thread.
EDIT
Looking at the doGet method and the two classes that you added subsequently, it looks like the processing is already sequential / serial. That is, the first "task" ends before the second "task" starts.
The problem with getConnection() throwing NullPointerException is (most likely) nothing to do with asynchrony. However I can't be sure of that without seeing the code of getConnection() and the complete stacktrace.
In Java, everything is normally executed in order, meaning that a given line of code will completely finish executing before the next line will start to do anything. The exception to this rule is when threads come into play. Threads allow multiple blocks of code to execute simultaneously. Because you aren't using any threads in your program (you'd know if you were, don't worry), it's guaranteed that the first two lines of code will complete before the next two begin to be executed.
So, your problem doesn't seem to be that your code is running "out of order". It's likely that your error is somewhere within the getConnection() method if that's what's throwing the NPE.
Here's an example (see Java Threads waiting value for details)
import java.util.concurrent.CountDownLatch;
class MyTask implements Runnable
{
CountDownLatch signal;
public MyTask(CountDownLatch signal)
{
this.signal = signal;
}
public void run()
{
System.out.println("starting task");
for (int i = 0; i < 10000000; i++)
Math.random();
//call when the task is done
signal.countDown();
}
}
public class Program
{
public static void main(String[] args) {
int workers = 1;
CountDownLatch signal = new CountDownLatch(workers);
new Thread(new MyTask(signal)).start();
try {
// Waits for all the works to finish ( only 1 in this case)
signal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task is done");
}
}
This is just a suggestion, maybe there's a better design:
import java.util.concurrent.CountDownLatch;
public class SchoolDAO extends DataAccessObject implements Runnable {
Long id;
CountDownLatch signal;
School searchResult;
public SchoolDAO(Long id, CountDownLatch signal)
{
this.id = id;
this.signal = signal;
}
public void run()
{
searchResult = findSchool(id);
signal.countDown();
}
// the other methods didn't change
}
Now you can call it inside doGet():
CountDownLatch signal = new CountDownLatch(1);
SchoolDAO dao = new SchoolDAO(id, signal);
new Thread(dao).start();
try {
signal.await();
} catch (InterruptedException e)
{
e.printStackTrace();
}
School result = dao.searchResult;

Categories

Resources