I launched my instance overnight to see how it handled things and when I came by this morning, I was facing a
Exception in thread "pool-535-thread-7" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:691)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:943)
at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:992)[info] application - Connecting to server A
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
The aim of my code is quite simple : Every 5 minutes, I connect to a list of remote server, send a request (via socket) and that's it.
Here's my code :
My "cron" task :
/** will create a new instance of ExecutorService every 5 minutes, loading all the websites in the database to check their status **/
/** Maybe that's where the problem is ? I need to empty (GC ?) this ExecutorService ? **/
Akka.system().scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), // Initial delay 0 milliseconds
Duration.create(5, TimeUnit.MINUTES), // Frequency 5 minutes
new Runnable() {
public void run() {
// We get the list of websites to check
Query<Website> query = Ebean.createQuery(Website.class, "WHERE disabled = false AND removed IS NULL");
query.order("created ASC");
List<Website> websites = query.findList(); // Can be 1, 10, 100, 1000. In my test case, I had only 9 websites.
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
for (Website website : websites) {
CheckWebsite task = new CheckWebsite(website);
executor.execute(task);
}
// This will make the executor accept no new threads
// and finish all existing threads in the queue
executor.shutdown();
}
},
Akka.system().dispatcher()
);
My CheckWebsite class :
public class CheckWebsite implements Runnable {
private Website website;
public CheckWebsite(Website website) {
this.website = website;
}
#Override
public void run() {
WebsiteLog log = website.checkState(); // This is where the request is made, I copy paste the code just after
if (log == null) {
Logger.error("OHOH, WebsiteLog should not be null for website.checkState() in CheckWebsite class :s");
return;
}
try {
log.save();
catch (Exception e) {
Logger.info ("An error occured :/");
Logger.info(e.getMessage());
e.printStackTrace();
}
}
}
My checkState() method in Website.class :
public WebsiteLog checkState() {
// Since I use Socket and the connection can hang indefinitely, I use an other ExecutorService in order to limit the time spent
// The duration is defined via Connector.timeout, Which will be the next code.
ExecutorService executor = Executors.newFixedThreadPool(1);
Connector connector = new Connector(this);
try {
final long startTime = System.nanoTime();
Future<String> future = executor.submit(connector);
String response = future.get(Connector.timeout, TimeUnit.MILLISECONDS);
long duration = System.nanoTime() - startTime;
return PlatformLog.getLastOccurence(this, response, ((int) duration/ 1000000));
}
catch (Exception e) {
return PlatformLog.getLastOccurence(this, null, null);
}
}
Here's the Connector.class. I removed useless part here (like Catches) :
public class Connector implements Callable<String> {
public final static int timeout = 2500; // WE use a timeout of 2.5s, which should be enough
private Website website;
public Connector(Website website) {
this.website = website;
}
#Override
public String call() throws Exception {
Logger.info ("Connecting to " + website.getAddress() + ":" + website.getPort());
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(website.getIp(), website.getPort()), (timeout - 50));
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = input.readLine();
socket.close();
return response;
}
catch (Exception e) {
e.printStackTrace();
throw e;
}
finally {
// I take the precaution to close the socket here in order to avoid a memory leak
// But if the previous ExecutorService force the close of this thread before
// I can't guarantee it will be closed :/
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
}
}
I'm new to Java multithreading so I probably made big mistake. I suspect some area that could be potentially the reason, but my lack of knowledge requires me to ask for your help :)
As a summary, here's the potentials areas :
Creating a new ExecutorService every 5 minutes. Maybe I can reuse the old one ? Or do I need to close the current one when finished (if so, how ?).
The fact that I create an ExecutorService that will create an ExecutorService (in the checkstate() method)
The fact that the Connector class can be (violently) stopped by the ExecutorService running it, if it takes too long, resulting in a socket not closed (and then a memory leak) ?
Also, as you can see, the exception occured for the thread "pool-535-thread-7" which mean it didn't happen soon.
I store the last_occured check in the database, and the creation of the log entry (in WebsiteLog), the delta is around 5 hours (so, for every 5 minutes, the thread crashed after around 60 calls).
Update : Here's the revisited checkState method to include the shutdown call :
public PlatformLog checkState() {
ExecutorService executor = Executors.newFixedThreadPool(1);
Connector connector = new Connector(this);
String response = null;
Long duration = null;
try {
final long startTime = System.nanoTime();
Future<String> future = executor.submit(connector);
response = future.get(Connector.timeout, TimeUnit.MILLISECONDS);
duration = System.nanoTime() - startTime;
}
catch (Exception e) {}
executor.shutdown();
if (duration != null) {
return WebsiteLog.getLastOccurence(this, response, (duration.intValue()/ 1000000));
}
else {
return WebsiteLog.getLastOccurence(this, response, null);
}
}
I'm not sure this is the only problem, but you are creating an ExecutorService in your checkState() method but you don't shut it down.
According to the JavaDocs for Executors.newFixedThreadPool():
The threads in the pool will exist until it is explicitly shutdown.
The threads staying alive will cause the ExecutorService not to be garbage collected (which would call shutdown() on your behalf. Hence you are leaking a thread each time this is called.
Related
This question already has answers here:
How to asynchronously call a method in Java
(12 answers)
Closed 5 years ago.
I have the following code that is making a call to two web services. Both web services return very large responses, so the response is taking quite a long time to return (one web service request is 8 seconds, the other is 12 seconds). The total execution time is 20 seconds as the requests are running in series and not parallel.
Is there any way I can modify my code to request the two web services asynchronously and be able to get the response processed in a time closer to 12 seconds than 20 seconds that it currently takes?
String listOfCities;
String listOfCountries;
try {
listOfCities = service.getListOfCities(host+"service/cities");
listOfCountries = service.getListOfCountries(host+"service/countries");
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
** Thanks for the responses, I feel this isn't a duplicate as I wanted to stop the execution of the two threads I was executing until both received a result from both. The solutions below show that. **
I would try something simple, like CompletableFuture:
import java.util.concurrent.CompletableFuture;
...
final CompletableFuture<String> listOfCities = CompletableFuture.supplyAsync(() -> service.getListOfCities(...));
final CompletableFuture<String> listOfCountries = CompletableFuture.supplyAsync(() -> service. getListOfCountries(...));
final CompletableFuture<Void> allCompleted = CompletableFuture.allOf(listOfCities, listOfCountries);
allCompleted.thenRun(() -> {
// whatever you want to do
});
See these examples for reference.
very simple implementation, For more advance you may want to take look at FutureTask
List<Thread> threadList = new ArrayList<>();
threadList.add(new Thread(new Runnable() {
#Override
public void run() {
try {
listOfCountries = service.getListOfCountries(host+"service/countries");
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
}
}));
threadList.add(new Thread(new Runnable() {
#Override
public void run() {
try {
listOfCities = service.getListOfCities(host+"service/cities");
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
}
}));
for (Thread t:threadList ){
t.start();
}
for (Thread t:threadList ){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//after both finish proceeds from here
Note the Strings Should be defined more globally (class level, not local variables)
Global variables of the class.
String listOfCities;
String listOfCountries;
In the function, the methods would be called like this,
try {//t is the object of the class like (Test t = new Test();)
new Thread(()-> t.listOfCities = service.getListOfCities(host+"service/cities");).start();
new Thread(()-> t.listOfCountries = service.getListOfCountries(host+"service/countries");).start();
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
Code example https://ideone.com/wB9SMa
By #AniketSahrawat
If you want the execution time in completion order I would advice you to use ListenableFuture from guava. Futures.inCompletionOrder will do the job.
Sample usage can look something like that:
ExecutorService es;
Callable<String> task1;
Callable<String> task2;
//...
ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(es);
List<ListenableFuture<String>> yourTasks = new ArrayList<>();
yourTasks.add(listeningExecutorService.submit(task1));
yourTasks.add(listeningExecutorService.submit(task2));
for(Future f: Futures.inCompletionOrder(yourTasks)){
//process your task in completion order now
}
I'm writing an IP scanner application and the process is taking long time so what i used at back scene of gui is service executor like:
public static List<Future<String>> checkThisIP(String ipStart, String ipEnd) throws UnknownHostException {
final ExecutorService es = Executors.newFixedThreadPool(10);
final List<Future<String>> futures = new ArrayList<>();
String ipStringStart;
String ipStringEnd;
String targetIpString;
//my update
ipStringStart = ipStart.substring(ipStart.lastIndexOf(".") + 1, ipStart.length());
ipStringEnd = ipEnd.substring(ipEnd.lastIndexOf(".") + 1, ipEnd.length());
targetIpString = ipStart.substring(0, ipStart.lastIndexOf(".") + 1);
if (!ipStart.equals(ipEnd)) {
for (int i = Integer.parseInt(ipStringStart); i <= Integer.parseInt(ipStringEnd); i++) {
String currentIp = targetIpString + i;
futures.add(runPingScan(es, currentIp));
}
} else {
futures.add(runPingScan(es, ipStart));
}
es.shutdown();
return futures;
}
public static Future<String> runPingScan(final ExecutorService es, final String ip) {
return es.submit(new Callable<String>() {
#Override
public String call() {
String returnMe = "";
//custom ping class
Ping p = new Ping();
//send message
p.SendReply(ip);
//IsReachable returns ture or false
if(p.IsReachable()){
returnMe=ip;
}
return returnMe;
}
});
}
This is the original laggy code action preformed using Jbutton:
// scan result is Future list returned from service executor
List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
for (final Future<String> f : scanResult) {
try {
ip = f.get();
if (!ip.equals("")) {
arp ARP = new arp();
PortScan openPort = new PortScan();
IP ipClass = new IP();
mac = ARP.getMac(ip);
manufacturer = ARP.getOUI(mac);
ports = openPort.checkIpForPorts(ip);
hostname = ipClass.hostname(ip);
title = ipClass.htmlTitle(ip);
Object[] data = {ip, mac, manufacturer, ports, hostname, title};
tableModel.addRow(data);
}
if (jFormattedTextField1.getText().equals(jFormattedTextField2.getText()) && ip.equals("")) {
JOptionPane.showMessageDialog(null, "<html>Can not ping the address ! <br> Server might be protected by <b>WAF</b>.</html>", "Alert", HEIGHT);
}
} catch (Exception ex) {
Logger.getLogger(gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
Running this code is good but when i attach it to Start Scan Button the gui lags, I googled and figured out to use Swing Worker. When i implemented the swing worker alone it killed the concurrency and when i implemented both the gui still lags. My question is there anyway to make the button (Swing worker) call the service executor to do the other processes ?
I've managed to solve my problem by implementing the swing worker and the function do in back ground will start a new thread for service executor and prevent the lag.
//The actionpreformed by the button
SwingWorker worker = new SwingWorker<Void, Void>() {
#Override
// All actions are done this method
protected Void doInBackground() throws Exception {
String ip = "";
String mac = "";
String manufacturer = "";
String ports = "";
String hostname = "";
String title = "";
tableModel.setRowCount(0);
PingScan p = new PingScan();
List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
for (final Future<String> f : scanResult) {
try {
ip = f.get();
if (!ip.equals("")) {
arp ARP = new arp();
PortScan openPort = new PortScan();
IP ipClass = new IP();
mac = ARP.getMac(ip);
manufacturer = ARP.getOUI(mac);
ports = openPort.checkIpForPorts(ip);
hostname = ipClass.hostname(ip);
title = ipClass.htmlTitle(ip);
Object[] data = {ip, mac, manufacturer, ports, hostname, title};
tableModel.addRow(data);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
return null;
}
};
worker.execute();
When i implemented the swing worker alone it killed the concurrency and when i implemented both the gui still lags.
There's two things to do here:
spreading your ping checks over multiple threads
split your task into independent sub-tasks
run sub-tasks in a thread-pool
collect results
detaching the whole operation from the event dispach thread
register user action (click, keypress), get data from text fields, build task
run task outside of the EDT
update the gui, showing the results
You're doing the first part with the ExecutorService, for some of your code. The second part is not done in your code, so the EDT will block until the whole operation is finished, making your gui lag.
You'll need to move this code to a swing worker, which runs the tasks in the executor:
List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
for (final Future<String> f : scanResult) {
try {
[...] // this is where the thread blocks, making your ui lag if it's the EDT
Object[] data = {ip, mac, manufacturer, ports, hostname, title};
First, move all blocking code to be handled by the executor's thread pool:
public static Future<Object[]> runPingScan(final ExecutorService es, final String ip) {
return es.submit(new Callable<Object[]>() {
#Override
public Object[] call() {
//custom ping class
Ping p = new Ping();
//send message
p.SendReply(ip);
//IsReachable returns ture or false
if(p.IsReachable()){
[...] // other blocking code
return {ip, mac, manufacturer, ports, hostname, title};
} else {
// special case, use null values or throw an exception
}
}
});
}
Then you can use the Simple Background Tasks tutorial code to detach the whole thing from the EDT:
SwingWorker worker = new SwingWorker<List<Object[]>, Void>() {
public List<Object[]> doInBackground() {
// -- this will run in another thread --
// submit ping checks to the executor
List<Future<Object[]>> scanResult = [...]
// get results, put them in a list, return it
List<Object[]> result = new ArrayList<>();
for(Future<Object[]> f : scanResult) {
result.add(f.get()); // blocking happens here, outside of the EDT
}
return result;
}
public void done() {
// -- this will run in the EDT --
// get() the list created above
// display the result in the gui
for(Object[] data : get()) {
tableModel.addRow(data);
}
}
};
What's not included here are special cases like a failed ping check, you'll need to handle them somehow. Every exception thrown from within your callables is rethrown when calling f.get(), wrapped in an ExecutionException. Using that for those special cases is probably your best option.
I have an method that can execute asynchronous request in fire and forget fashion.
Method is implemented as following :
private void publishWorkItem(final Object payload, final ZkWorkCompleteCallback callback)
{
if (payload == null)
throw new NullPointerException();
final ExecutorService executor = Executors.newSingleThreadExecutor(PUBLISH_WORK_THREAD_FACTORY);
try
{
executor.execute(() -> {
try
{
if (callback != null)
{
final ZkWorkItem retval = publishWorkItem(payload);
callback.onCompleted(retval);
}
}
catch (final InterruptedException e)
{
// suppressed
}
catch (final Exception e)
{
LOGGER.error("Unhandled exception", e);
if (callback != null)
callback.onError(e);
}
});
}
finally
{
executor.shutdown();
}
}
Issue is that I am creating new ExecutorService Executors.newSingleThreadExecutor for each async request instead of using fixed thread pool. Reason for that is that publishWorkItem(payload) method uses a CountDownLatch#await() which in turn will block the executing thread because is waits for Watcher to finish. This could quickly exhaust fixed size pool.
Simplified code of publishWorkItem(payload)
final CountDownLatch latch = new CountDownLatch(1);
zkClient.exists(pathToWatch, new Watcher()
{
#Override
public void process(final WatchedEvent event)
{
try
{
extractAndDelete(baos, event.getPath());
}
catch (final Exception e)
{
LOGGER.error("Unable to perform cleanup", e);
}
finally
{
latch.countDown();
}
}
}, true);
------ THIS IS THE PROBLEM (Blocks current thread) ------
latch.await();
So my question is: Are there better approaches to this type of problem.
I did profile the application and I don't see any performance issues, my concern was that it was creating large number of threads.
Why don't you use a ExecutorService.newCachedThreadPool()?
According to the javadoc, it suits your use-case
These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks ... will reuse previously constructed threads if available
Instead of creating a new single thread pool on each call of publishWorkItem(), you create a cached thread pool once and use for all your queries. The number of threads is capped by Integer.MAX_VALUE, so you will not be limited like with fixed thread pool, but it should be creating less threads overall.
I'm a tapestry-hibernate user and I'm experiencing an issue where my session remains closed once I exceed my Executors.newFixedThreadPool(1);
I have the following code which will work perfectly for the first thread while the remaining threads experience a closed session. If I increase the thread pool to 10, all the threads will run without issue. As soon as I exceed the fixedThreadPool, I get the session closed exception. I do not know how to open it since it's managed by tapestry-hibernate. If I use newCachedThreadPool, everything works perfectly. Does anybody know what might be happening here?
public void setupRender() {
ExecutorService executorService = Executors.newFixedThreadPool(1);
final ConcurrentHashMap<String, Computer> map = new ConcurrentHashMap<>();
final String key = "myKey";
final Date date = new Date();
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final int thread = i;
Future future = executorService.submit(new Callable() {
#Override
public String call() {
try {
Computer computer = new Computer("Test Computer thread");
computer = getComputer(map, key, key, computer);
Monitor monitor = new Monitor();
monitor.setComputer(computer);
session.save(monitor);
session.flush();
System.out.println("thread " + thread);
try {
sessionManager.commit();
} catch (HibernateException ex) {
sessionManager.abort();
} finally {
session.close();
}
} catch (Exception ex) {
System.out.println("ex " + ex);
}
System.out.println( new Date().getTime() - date.getTime());
return "completed";
}
});
futures.add(future);
}
for(Future future : futures) {
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(MultiThreadDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public synchronized Computer getComputer(ConcurrentHashMap<String, Computer> map, String key, String thread, Computer computer) {
if (map.putIfAbsent(key, computer) == null) {
session.save(computer);
} else {
computer = map.get(key);
}
return computer;
}
I've told you this before.... you MUST either use ParallelExecutor OR call PerThreadManager.cleanup(). You need to understand that tapestry-hibernate has PerThread scoped services that MUST be cleaned up if you are using them outside of a normal request/response (or ParallelExecutor).
I also don't think you should be calling session.close(). You should mimmic CommitAfterWorker.
It would probably look something like:
#Inject PerThreadManager perThreadManager;
#Inject HibernateSessionManager sessionManager; // this is a proxy to a per-thread value
#Inject Session session; // this is a proxy to a per-thread value
public void someMethod() {
ExecutorService executorService = ...;
executorService.submit(new Callable() {
public String call() {
try {
Monitor monitor = ...
session.save(monitor);
session.flush(); // optional
sessionManager.commit();
} catch (Exception ex) {
sessionManager.abort();
} finally {
// this allows Session and HibernateSessionManager to
// clean up after themselves
perThreadManager.cleanup();
}
return ...
}
});
}
If you choose to use the ParallelExecutor (and Invokable) instead of Executors.newFixedThreadPool(1) you can remove the references to PerThreadManager since it automatically cleans up the thread.
This question already has answers here:
How to run a background task in a servlet based web application?
(5 answers)
Closed 7 years ago.
EDIT:
The current code is the working solution, the one which does not block the application, it
incorporates the suggestion made in the approved answer.
I want a background thread to download an MS Access database continuously, while my tomcat 7 web application is running, the thread does download the database, however it seems to block my application's startup as I'm unable to access any page from the service, this is the code that I'm using:
public class DatabaseUpdater implements ServletContextListener {
private Thread thread = null;
private final Runnable updater = new Runnable() {
private boolean hasExpired(File mdbFile) throws IOException {
if (!mdbFile.exists())
return true;
Long ttl = Long.parseLong(Configuration.getValueForOS("db.http-expiration"));
Date now = new Date();
Date fileDate = new Date(mdbFile.lastModified());
return (now.getTime() - fileDate.getTime()) > ttl;
}
#Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted())
throw new RuntimeException("Application Shutdown");
try {
String databases[] = new String[]{"database1", "database2"};
for (String database : databases) {
String fileName = database + "." + StringUtil.randomString(8) + ".mdb";
String fileLocation = Configuration.getValueForOS("db.path");
File mdbFile = new File(fileLocation, fileName);
File currentDatabaseFile = new File(fileLocation, database + ".mdb");
if (hasExpired(currentDatabaseFile)) {
URL url = new URL(Configuration.getValueForOS("db.url." + database));
InputStream in = url.openConnection().getInputStream();
OutputStream out = new FileOutputStream(mdbFile);
FileUtil.streamBridge(in, out);
FileUtil.close(in, out);
while (currentDatabaseFile.exists() && !currentDatabaseFile.delete()) ;
while (!mdbFile.renameTo(currentDatabaseFile)) ;
}
}
// Put the thread to sleep so the other threads do not starve
Thread.sleep(Long.parseLong(
Configuration.getValueForOS("db.http-expiration"));
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
this.thread = new Thread(updater);
thread.start();
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
if (this.thread.isAlive())
this.thread.interrupt();
}
}
What could be causing?
I based my implementation on this question: Background Thread for a Tomcat servlet app
Given that your code loops forever, you're probably starving all the other threads in the VM. Try sleeping the thread once in a while.