I searched now for a while with google but i could not get it to work. My approach is to have a Multithread software which collects data on one Thread and then execute the batch query for Mysql in a second thread while the first thread is going on collecting data. Goal should it be to use as less RAM as possible for millions of inserts. In My data collection Process i use one Object of MYSQLInsertThread and i insert Data like this:
String[] types = {"Long", "Long"};
int[] pos = {1, 1};
Object[] values = {123, 456};
nodeTagsInsertThread.addBatch(types, pos, values);
The first call works, if I set the batchCount to 100 i got 104 entrys in my Database but that are the only entrys which my class produces (it should import 5 million entrys!
public class MYSQLInsertThread implements Runnable
{
private Thread t;
private String threadName = "MYSQL InsertThread";
private String query;
private PreparedStatement pstmt;
private PreparedStatement pstmt2;
private long batchCount;
private long maxBatchAmount;
private Boolean pstmt1Active = true;
private Boolean isRunning = false;
public MYSQLInsertThread(String name, String query, Connection conn, int maxBatchAmount) throws SQLException
{
threadName = name;
this.pstmt = conn.prepareStatement(query);
this.pstmt2 = conn.prepareStatement(query);
this.query = query;
this.maxBatchCount = maxBatchAmount;
System.out.println("Creating Thread: " + name);
}
public synchronized void addBatch(String[] types, int[] positions, Object[] values) throws SQLException
{
PreparedStatement _pstmt;
if(pstmt1Active)
{
_pstmt = pstmt;
}
else
{
_pstmt = pstmt2;
}
if(_pstmt != null)
{
for(int i=0;i<types.length; i++)
{
switch(types[i])
{
case "string":
case "String":
_pstmt.setString(positions[i], (String)values[i]);
break;
case "long":
case "Long":
_pstmt.setLong(positions[i], (long)values[i]);
break;
case "int":
case "Integer":
_pstmt.setInt(positions[i], (int)values[i]);
break;
case "double":
case "Double":
_pstmt.setDouble(positions[i], (double)values[i]);
break;
default:
break;
}
}
_pstmt.addBatch();
batchCount++;
if(batchCount % maxBatchCount == 0)
{
System.out.println("["+ this.threadName +"]Adding " + batchCount + " Entrys to DB" );
this.executeBatch();
}
}
else
{
System.err.println("[MYSQLInsertThread]Error PreparedStatment is NULL, Parameter could not be added");
}
}
public synchronized void executeBatch()
{
PreparedStatement _pstmt;
if(pstmt1Active)
{
_pstmt = pstmt;
}
else
{
_pstmt = pstmt2;
}
if(_pstmt != null)
{
if(isRunning)System.out.println("Waiting for previous Batch Execution to finish");
while(isRunning)
{
System.out.print(".");
try {
Thread.sleep(100);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
this.start();
System.out.println("Execution Started Successfully");
}
else
{
System.err.println("[" + this.threadName + "]PSTMT is NULL");
}
}
#Override
public void run()
{
PreparedStatement _pstmt;
if(pstmt1Active)
{
_pstmt = pstmt;
}
else
{
_pstmt = pstmt2;
}
if(_pstmt != null)
{
isRunning = true;
pstmt1Active = !pstmt1Active;
try
{
_pstmt.executeBatch();
}
catch(Exception e)
{
e.printStackTrace();
}
isRunning = false;
}
}
public void start()
{
if(t == null)
{
t = new Thread(this, threadName);
t.start();
}
}
}
I found a solution now by myself searching a bit through youtube videos :D
I made a new Class which hold my PreparedStatements. If one Statement is executing a flag is preivously set. If the second Statemet wants to execute the Batch now but the previous Statement is still running it makes the collecting thread waiting for a notify of the writing process. The writing process notifys after finishing the execution of the statements!
Here is my Code:
public class ThreadPreparedStatement
{
private String query;
private String threadName;
private PreparedStatement pstmt1;
private PreparedStatement pstmt2;
private boolean pstmt1Active;
private boolean isRunning;
private long maxBatchAmount;
private long batchCount;
public ThreadPreparedStatement(String threadName, String query, Connection conn, long maxBatchAmount) throws SQLException
{
this.threadName = threadName;
this.pstmt1 = conn.prepareStatement(query);
this.pstmt2 = conn.prepareStatement(query);
this.maxBatchAmount = maxBatchAmount;
this.query = query;
this.batchCount = 0;
}
public synchronized void addParameters(String[] types, int[] positions, Object[] values) throws SQLException
{
PreparedStatement _pstmt;
if(pstmt1Active)
{
_pstmt = pstmt1;
}
else
{
_pstmt = pstmt2;
}
if(_pstmt != null)
{
for(int i=0;i<types.length; i++)
{
switch(types[i])
{
case "string":
case "String":
_pstmt.setString(positions[i], (String)values[i]);
break;
case "long":
case "Long":
_pstmt.setLong(positions[i], (long)values[i]);
break;
case "int":
case "Integer":
_pstmt.setInt(positions[i], (int)values[i]);
break;
case "double":
case "Double":
_pstmt.setDouble(positions[i], (double)values[i]);
break;
default:
break;
}
}
_pstmt.addBatch();
batchCount++;
if(batchCount % maxBatchAmount == 0)
{
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
try
{
executeBatch(_pstmt);
}catch(Exception e)
{
e.printStackTrace();
}
}
});
t.start();
}
}
else
{
System.err.print("Error Prepared Statements are both NULL");
}
}
public synchronized void executeAllBatches()
{
try
{
if(isRunning)
{
try
{
wait(); //wait for finish execution
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
isRunning = true;
pstmt1.executeBatch();
pstmt2.executeBatch();
isRunning = false;
notify();
}catch(Exception e)
{
}
}
public synchronized void executeBatch(PreparedStatement _pstmt) throws SQLException
{
System.out.println("["+ this.threadName +"]Adding " + batchCount + " Entrys to DB" );
if(isRunning)
{
try
{
wait(); //wait for finish execution
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
pstmt1Active = !pstmt1Active;
isRunning = true;
_pstmt.executeBatch(); //execute Query Batch
isRunning = false;
notify(); //notify that Batch is executed
}
}
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am pretty new to Object Programming and Java, so I am here to gather your advice and feedback. Basically I am trying to write a background service which performs different tasks at different intervals. I'm just not 100% sure of what I am doing is following the coding standards or is efficient.
Main / Start Class:
public class Start {
public static void main(String[] args) {
Service s = new Service();
s.Start();
}
}
Database Class:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Database {
/* Database settings */
private final String HOSTNAME = "localhost";
private final String DATABASE = "java_database";
private final String USERNAME = "java_username";
private final String PASSWORD = "java_password";
/* Database connection */
public Connection getConnection() {
try {
return DriverManager.getConnection("jdbc:mysql://" + HOSTNAME + "/" + DATABASE + "?user=" + USERNAME + "&password=" + PASSWORD + "&useSSL=false&useUnicode=true&characterSetResults=utf8");
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}
}
Service Class:
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Service {
private int taskId;
private int taskType;
/* Start Service */
public void Start() {
try {
System.out.println("Starting Service...");
while(true) {
System.out.print("Checking for tasks... ");
getNextTask();
if (this.taskId > 0) {
System.out.println("Task ID " + this.taskId + " found.");
switch (this.taskType) {
case 1:
System.out.println("Task 1");
SampleTask s = new SampleTask();
s.Start();
s = null;
break;
default:
System.out.println("Error: Unknown Task");
}
setUsedTask();
} else {
System.out.println("No tasks to perform at this time.");
}
this.taskId = 0;
this.taskType = 0;
Thread.sleep(5000);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
/* Gets the next available task from the database */
public void getNextTask() {
try {
Database db = new Database();
String query = "select taskId, taskType "
+ "from tasks "
+ "where (time_to_sec(timediff(now(), taskLastRun)) > taskFrequency or taskLastRun is null) and taskEnabled = 1 "
+ "limit 1";
Statement stmt = db.getConnection().createStatement();
ResultSet rset = stmt.executeQuery(query);
if (rset.next()) {
this.taskId = rset.getInt(1);
this.taskType = rset.getInt(2);
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
/* Set task as complete */
public void setUsedTask() {
try {
Database db = new Database();
String query = "update tasks "
+ "set taskLastRun = now() "
+ "where taskId = ? "
+ "limit 1";
PreparedStatement pstmt = db.getConnection().prepareStatement(query);
pstmt.setInt(1, this.taskId);
pstmt.executeUpdate();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
Consider replacing your Thread.sleep() approach with a wait() and notify() approach as discussed here.
public class Service {
private int taskId;
private int taskType;
private final Object serviceMonitor;
/* Start Service */
public void Start() {
synchronized(serviceMonitor){
try {
System.out.println("Starting Service...");
while(true) {
System.out.print("Checking for tasks... ");
getNextTask();
if (this.taskId > 0) {
System.out.println("Task ID " + this.taskId + " found.");
switch (this.taskType) {
case 1:
System.out.println("Task 1");
SampleTask s = new SampleTask();
s.Start();
s = null;
break;
default:
System.out.println("Error: Unknown Task");
}
setUsedTask();
} else {
System.out.println("No tasks to perform at this time.");
}
this.taskId = 0;
this.taskType = 0;
serviceMonitor.wait();
}
}
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public void getNextTask() {
synchronized(serviceMonitor){
try {
Database db = new Database();
String query = "select taskId, taskType "
+ "from tasks "
+ "where (time_to_sec(timediff(now(), taskLastRun)) > taskFrequency or taskLastRun is null) and taskEnabled = 1 "
+ "limit 1";
Statement stmt = db.getConnection().createStatement();
ResultSet rset = stmt.executeQuery(query);
if (rset.next()) {
this.taskId = rset.getInt(1);
this.taskType = rset.getInt(2);
serviceMonitor.notifyAll();
}
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
public class Main {
public static void main(String[] args) {
Service service = new Service(Arrays.asList(new SampleTask(),new AnotherTask()));
service.execute();
}
}
class Service {
private List<Task> taskList;
public Service(List<Task> taskList) {
this.taskList = taskList;
}
public void addTask(Task task) {
taskList.add(task);
}
public void execute() {
for (Task task : taskList) {
new Timer().schedule(task, task.getDelay(), task.getPeriod());
}
}
public void clearTasks() {
taskList.clear();
}
}
abstract class Task extends TimerTask {
abstract long getDelay();
abstract long getPeriod();
}
class SampleTask extends Task {
public void run() {
System.out.println("Sample task executed");
}
long getDelay() {
return 1000;
}
long getPeriod() {
return 60000;
}
}
class AnotherTask extends Task {
public void run() {
System.out.println("Another task is executed");
}
long getDelay() {
return 1000;
}
long getPeriod() {
return 500000;
}
}
I have 1.5 million records in my mysql table. I'm trying to read all the records in a batch process i.e,planning to read 1000 records in a batch and print those records in console.
For this I'm planning to implement multithreading concept using java. How can I implement this?
In MySQL you get all records at once or you get them one by one in a streaming fashion (see this answer). Alternatively, you can use the limit keyword for chunking (see this answer).
Whether you use streaming results or chunking, you can use multi-threading to process (or print) data while you read data. This is typically done using a producer-consumer pattern where, in this case, the producer retrieves data from the database, puts it on a queue and the consumer takes the data from the queue and processes it (e.g. print to the console).
There is a bit of administration overhead though: both producer and consumer can freeze or trip over an error and both need to be aware of this so that they do not hang forever (potentially freezing your application). This is where "reasonable" timeouts come in ("reasonable" depends entirely on what is appropriate in your situation).
I have tried to put this in a minimal running example, but it is still a lot of code (see below). There are two commented lines that can be used to test the timeout-case. There is also a refreshTestData variable that can be used to re-use inserted records (inserting records can take a long time).
To keep it clean, a lot of keywords like private/public are omitted (i.e. these need to be added in non-demo code).
import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FetchRows {
private static final Logger log = LoggerFactory.getLogger(FetchRows.class);
public static void main(String[] args) {
try {
new FetchRows().print();
} catch (Exception e) {
e.printStackTrace();
}
}
void print() throws Exception {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Properties dbProps = new Properties();
dbProps.setProperty("user", "test");
dbProps.setProperty("password", "test");
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", dbProps)) {
try (Statement st = conn.createStatement()) {
prepareTestData(st);
}
// https://stackoverflow.com/a/2448019/3080094
try (Statement st = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY)) {
st.setFetchSize(Integer.MIN_VALUE);
fetchAndPrintTestData(st);
}
}
}
boolean refreshTestData = true;
int maxRecords = 5_555;
void prepareTestData(Statement st) throws SQLException {
int recordCount = 0;
if (refreshTestData) {
st.execute("drop table if exists fetchrecords");
st.execute("create table fetchrecords (id mediumint not null auto_increment primary key, created timestamp default current_timestamp)");
for (int i = 0; i < maxRecords; i++) {
st.addBatch("insert into fetchrecords () values ()");
if (i % 500 == 0) {
st.executeBatch();
log.debug("{} records available.", i);
}
}
st.executeBatch();
recordCount = maxRecords;
} else {
try (ResultSet rs = st.executeQuery("select count(*) from fetchrecords")) {
rs.next();
recordCount = rs.getInt(1);
}
}
log.info("{} records available for testing.", recordCount);
}
int batchSize = 1_000;
int maxBatchesInMem = 3;
int printFinishTimeoutS = 5;
void fetchAndPrintTestData(Statement st) throws SQLException, InterruptedException {
final BlockingQueue<List<FetchRecordBean>> printQueue = new LinkedBlockingQueue<List<FetchRecordBean>>(maxBatchesInMem);
final PrintToConsole printTask = new PrintToConsole(printQueue);
new Thread(printTask).start();
try (ResultSet rs = st.executeQuery("select * from fetchrecords")) {
List<FetchRecordBean> l = new LinkedList<>();
while (rs.next()) {
FetchRecordBean bean = new FetchRecordBean();
bean.setId(rs.getInt("id"));
bean.setCreated(new java.util.Date(rs.getTimestamp("created").getTime()));
l.add(bean);
if (l.size() % batchSize == 0) {
/*
* The printTask can stop itself when this producer is too slow to put records on the print-queue.
* Therefor, also check printTask.isStopping() to break the while-loop.
*/
if (printTask.isStopping()) {
throw new TimeoutException("Print task has stopped.");
}
enqueue(printQueue, l);
l = new LinkedList<>();
}
}
if (l.size() > 0) {
enqueue(printQueue, l);
}
} catch (TimeoutException | InterruptedException e) {
log.error("Unable to finish printing records to console: {}", e.getMessage());
printTask.stop();
} finally {
log.info("Reading records finished.");
if (!printTask.isStopping()) {
try {
enqueue(printQueue, Collections.<FetchRecordBean> emptyList());
} catch (Exception e) {
log.error("Unable to signal last record to print.", e);
printTask.stop();
}
}
if (!printTask.await(printFinishTimeoutS, TimeUnit.SECONDS)) {
log.error("Print to console task did not finish.");
}
}
}
int enqueueTimeoutS = 5;
// To test a slow printer, see also Thread.sleep statement in PrintToConsole.print.
// int enqueueTimeoutS = 1;
void enqueue(BlockingQueue<List<FetchRecordBean>> printQueue, List<FetchRecordBean> l) throws InterruptedException, TimeoutException {
log.debug("Adding {} records to print-queue.", l.size());
if (!printQueue.offer(l, enqueueTimeoutS, TimeUnit.SECONDS)) {
throw new TimeoutException("Unable to put print data on queue within " + enqueueTimeoutS + " seconds.");
}
}
int dequeueTimeoutS = 5;
class PrintToConsole implements Runnable {
private final BlockingQueue<List<FetchRecordBean>> q;
private final CountDownLatch finishedLock = new CountDownLatch(1);
private volatile boolean stop;
public PrintToConsole(BlockingQueue<List<FetchRecordBean>> q) {
this.q = q;
}
#Override
public void run() {
try {
while (!stop) {
List<FetchRecordBean> l = q.poll(dequeueTimeoutS, TimeUnit.SECONDS);
if (l == null) {
log.error("Unable to get print data from queue within {} seconds.", dequeueTimeoutS);
break;
}
if (l.isEmpty()) {
break;
}
print(l);
}
if (stop) {
log.error("Printing to console was stopped.");
}
} catch (Exception e) {
log.error("Unable to print records to console.", e);
} finally {
if (!stop) {
stop = true;
log.info("Printing to console finished.");
}
finishedLock.countDown();
}
}
void print(List<FetchRecordBean> l) {
log.info("Got list with {} records from print-queue.", l.size());
// To test a slow printer, see also enqueueTimeoutS.
// try { Thread.sleep(1500L); } catch (Exception ignored) {}
}
public void stop() {
stop = true;
}
public boolean isStopping() {
return stop;
}
public void await() throws InterruptedException {
finishedLock.await();
}
public boolean await(long timeout, TimeUnit tunit) throws InterruptedException {
return finishedLock.await(timeout, tunit);
}
}
class FetchRecordBean {
private int id;
private java.util.Date created;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public java.util.Date getCreated() {
return created;
}
public void setCreated(java.util.Date created) {
this.created = created;
}
}
}
Dependencies:
mysql:mysql-connector-java:5.1.38
org.slf4j:slf4j-api:1.7.20 (and to get logging shown in console: ch.qos.logback:logback-classic:1.1.7 with ch.qos.logback:logback-core:1.1.7)
This is my code by now:
public class discoverRunnable implements Runnable{
InetAddress address = null;
boolean discovered;
public discoverRunnable(InetAddress address){
this.address = address;
boolean discovered = false;
}
#Override
public void run(){
//some crazy stuff
//may set discovered = true
}
}
How can I return the Value of "discovered" to use it within a Thread now?
It should work on a PC without using Android archives.
You can use Callable instead of Runnable
public class DiscoverRunnable implements Callable<Boolean> {
InetAddress address = null;
boolean discovered;
public DiscoverRunnable(InetAddress address){
this.address = address;
boolean discovered = false;
}
#Override
public Boolean call(){
//some crazy stuff
//may set discovered = true
return discovered;
}
}
I couldn't get a member variable to be accessible after a thread finishes a Runnable. I can get the Callable to return future with value, without a problem. So, I would agree, always use a Callable in these cases where you need a value from a finished runnable.
import java.util.*;
import java.util.concurrent.*;
class Main
{
public static void main(String[] args) {
ExecutorService ex = Executors.newFixedThreadPool(4);
Runnable r1 = new Runnable() {
private boolean flag = false;
#Override
public void run() {
try {
System.out.println("Thread: " + Thread.currentThread().getName());
Thread.sleep((long)(Math.random() * 1000));
flag = true;
} catch (InterruptedException ie) {
// do nothing
}
}
public boolean getFlag() {
return flag;
}
};
Callable<Boolean> c1 = new Callable<Boolean>() {
private boolean flag = false;
#Override
public Boolean call() {
try {
System.out.println("Thread: " + Thread.currentThread().getName());
Thread.sleep((long)(Math.random() * 1000));
flag = true;
} catch (InterruptedException ie) {
// do nothing
}
return getFlag();
}
public boolean getFlag() {
return flag;
}
};
ex.submit(r1);
Future<Boolean> f = ex.submit(c1);
ex.shutdown();
if (c1 != null) {
try {
System.out.println("Callable future-get: "
+ f.get()); //WORKS!: shows boolean value returned from future
System.out.println("Callable direct-var: "
+ ((Callable<Boolean>) c1).flag); //FAIL
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
if (r1 != null) System.out.println("Runnable result: "
+ ((Runnable) r1).flag); //FAIL
}
}
In Kotlin
fun checkWebUrl(): Boolean {
val futureResult = FutureTask<Boolean>(Callable<Boolean> {
webview_entry.url.startsWith("https://developer.android.com/reference/java/util/concurrent/FutureTask")
})
return futureResult.get()
}
I´m try to build a application which, by threads, are listening to directory for changes. Everything works fine, but there is a little bug. I´m very new to the whole threads-thing... So, this problem probably based on my ignorance...
The program can se all the changes in the picked directory, BUT, when the threads are running, i cant modify the files inside the directory... Those are locked in the process...
I will be very happy if someone perhaps can give me some tips in how i can solve this.
Thank you in advance
DirWatch
public class DirWatch implements Runnable{
Path dirPath;
private boolean run = true;
private boolean created = false;
private boolean modified = false;
private boolean compressed = false;
private boolean isJSON = false;
/**
*
* #param path
* #throws IOException
*/
public void setWatchPath(String path) throws IOException {
dirPath = Paths.get(path);
try {
Boolean isFolder = (Boolean) Files.getAttribute(dirPath, "basic:isDirectory", new LinkOption[]{NOFOLLOW_LINKS});
if (!isFolder) {
throw new IllegalArgumentException("Path: " + dirPath + " is not a folder");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
System.out.println("Watching path: " + path);
}
public void setDirPathWatchRun(boolean run){
this.run = run;
}
public boolean isCreated() {
return created;
}
public void setCreated(boolean created) {
this.created = created;
}
public boolean isModified() {
return modified;
}
public void setModified(boolean modified) {
this.modified = modified;
}
public boolean isCompressed() {
return compressed;
}
public void setCompressed(boolean compressed) {
this.compressed = compressed;
}
public boolean isJSON() {
return isJSON;
}
public void setJSON(boolean JSON) {
isJSON = JSON;
}
private void checkFileType(String fileName){
String extension = fileName.substring(fileName.length() - 4);
if(extension.equalsIgnoreCase(FILE_TYPE.TAR.getFileType())){
setCompressed(true);
System.out.println(extension);
}
if(extension.equalsIgnoreCase(".json")){
setJSON(true);
}
}
#Override
public void run() {
FileSystem fs = dirPath.getFileSystem ();
try(WatchService service = fs.newWatchService()) {
dirPath.register(service, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
WatchKey key = null;
while(run) {
key = service.take();
WatchEvent.Kind<?> kind = null;
for(WatchEvent<?> watchEvent : key.pollEvents()) {
kind = watchEvent.kind();
if (OVERFLOW == kind) {
System.out.println("OVERFLOW");
continue;
} else if (ENTRY_CREATE == kind) {
System.out.println("New path created: " + watchEvent.context().toString());
setCreated(true);
checkFileType(watchEvent.context().toString());
} else if (ENTRY_DELETE == kind){
System.out.println("Path deleted: " + watchEvent.context().toString());
setModified(true);
checkFileType(watchEvent.context().toString());
} else if (ENTRY_MODIFY == kind) {
System.out.println("Path modified: " + watchEvent.context().toString());
setModified(true);
checkFileType(watchEvent.context().toString());
}
}
if(!key.reset()) {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Method Watch in another class
private void watch() throws IOException {
watchJSON = new DirWatch();
watchTAR = new DirWatch();
watchTAR.setWatchPath(serverArgs.getCompressedPath());
watchJSON.setWatchPath(serverArgs.getExtractedPath());
Runnable checkSourceActions = new Runnable() {
#Override
public void run() {
while(true) {
if (watchJSON.isCreated() || (watchJSON.isModified())) {
server();
}
if(watchTAR.isCreated() || (watchTAR.isModified())) {
extractFiles(fileHandler);
createManifest(fileHandler);
server();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread1 = new Thread(watchJSON);
Thread thread3 = new Thread(watchTAR);
Thread thread2 = new Thread(checkSourceActions);
thread1.start();
thread2.start();
thread3.start();
}
When I try to change the file while the program is running
Here I have two run methods which should synchronize each other.
Poller Class:
*/
public void run() {
int seqId = 0;
while(true) {
List<KpiMessage> list = null;
try{
if(!accumulator.isUsed){
try {
list = fullPoll(seqId);
if (!list.isEmpty()) {
seqId = list.get(0).getSequence();
accumulator.manageIngoing(list);
}
System.out.println("Updated");
wait();
} catch (Exception e1) {
e1.printStackTrace();
}
}
} catch (Exception e){
// TODO:
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
/**
* Method which defines polling of the database and also count the number of Queries
* #param lastSeq
* #return pojo col
* #throws Exception
*/
public List<KpiMessage> fullPoll(int lastSeq) throws Exception {
Statement st = dbConnection.createStatement();
System.out.println("Polling");
ResultSet rs = st.executeQuery("Select * from msg_new_to_bde where ACTION = 814 and
STATUS = 200 order by SEQ DESC");
List<KpiMessage> pojoCol = new ArrayList<KpiMessage>();
try {
while (rs.next()) {
KpiMessage filedClass = convertRecordsetToPojo(rs);
pojoCol.add(filedClass);
}
for (KpiMessage pojoClass : pojoCol) {
System.out.print(" " + pojoClass.getSequence());
System.out.print(" " + pojoClass.getTableName());
System.out.print(" " + pojoClass.getAction());
System.out.print(" " + pojoClass.getKeyInfo1());
System.out.print(" " + pojoClass.getKeyInfo2());
System.out.print(" "+ pojoClass.getStatus());
System.out.println(" " + pojoClass.getEntryTime());
}
} finally {
try {
st.close();
rs.close();
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
Processing and Updating Class:
public void run() {
while(true){
try {
while(!accumulator.isUsed)
{
try {
System.out.println("Waiting for new outgoingmessages");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Collection<KpiMessage> outgoingQueue = generate(accumulator.outgoingQueue);
accumulator.manageOutgoing(outgoingQueue, dbConnection);
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
}
I have a logical error:
The poller is polling not only for new messsage but also reads the DB again and again from the first.
Also Updates again and again.
How to solve this synchronization problem.
Alternatively you could use a BlockingQueue to transfer the data between threads.
See BlockingQueue for details.
// The end of the list.
private static final Integer End = -1;
static class Producer implements Runnable {
final Queue<Integer> queue;
private int i = 0;
public Producer(Queue<Integer> queue) {
this.queue = queue;
}
#Override
public void run() {
try {
for (int i = 0; i < 1000; i++) {
queue.add(i++);
Thread.sleep(1);
}
// Finish the queue.
queue.add(End);
} catch (InterruptedException ex) {
// Just exit.
}
}
}
static class Consumer implements Runnable {
final Queue<Integer> queue;
private int i = 0;
public Consumer(Queue<Integer> queue) {
this.queue = queue;
}
#Override
public void run() {
boolean ended = false;
while (!ended) {
Integer i = queue.poll();
if ( i != null ) {
ended = i == End;
System.out.println(i);
}
}
}
}
public void test() throws InterruptedException {
Queue queue = new LinkedBlockingQueue();
Producer p = new Producer(queue);
Consumer c = new Consumer(queue);
Thread pt = new Thread(p);
Thread ct = new Thread(c);
// Start it all going.
pt.start();
ct.start();
// Close it down
pt.join();
ct.join();
}
You should synchronize or rather hold the lock or monitor for the object that you are calling wait() or notify() on.
Here is what will help you : wait() throwing IllegalArgumentException
synchronized(lockObject){
lockObject.wait(); //you should hold the lock to be able to call wait()
}