I am creating a thread in Java for Android using following code:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
String TAG = "WorkerThread";
Integer c = 1;
MainActivity.logInMainThread(TAG, "Initial state of Worker thread is " + Thread.currentThread().getState().toString(), "DEBUG");
Authentication authentication = new Authentication();
Boolean result = authentication.authenticate(bindDN, password);
Validation validate = MainActivity.getValidationObject(c);
validate.setResult(result);
Thread.currentThread().interrupt();
TAG = null;
c = null;
authentication = null;
result = null;
validate = null;
System.gc();
return;
}
});
As you can see I tried using Thread.interrupt and clearing all the variables and calling the Garbage Collector and returning but I still receive
W/System: A resource failed to call close.
after the thread is done, how do I close it properly? If I call Thread.stop it throws an Error and the method is deprecated, same with Thread.destroy.
How can I close my thread and stop it from becoming a corpse?
A thread should terminate when it's run method (or the Runnable's run method) terminates.
Your cleanup is the last few expressions in the run method, and it may be they are never executed since is the thread gets interrupted (an InterruptedException is thrown). You are doing it by invoking Thread.currentThread().interrupt();.
So your run method should look like
public void run() {
// at least declare the variables so their scope lasts until the finally block
String TAG = "WorkerThread";
Integer c = 1;
Authentication authentication = null;
try { // perform your actions
MainActivity.logInMainThread(TAG, "Initial state of Worker thread is " + Thread.currentThread().getState().toString(), "DEBUG");
authentication = new Authentication();
Boolean result = authentication.authenticate(bindDN, password);
Validation validate = MainActivity.getValidationObject(c);
validate.setResult(result);
} finally { // perform your cleanup
TAG = null;
c = null;
authentication = null;
result = null;
validate = null;
System.gc();
}
}
Related
The code below will make it more clear:
public static String TCMResponse(String params, final Context c) {
final String url = "https://115.248.161.106/ois/API/android/" + params;
new Thread(new Runnable() {
#Override
public void run() {
String response="";
try {
Document doc = Jsoup.connect(url).validateTLSCertificates(false).timeout(6000).get();
response = doc.text();
}
catch (IOException e) {
Log.d("Err","External OIS not reachable!");
}
// I want to return 'response' here, for the TCMResponse()
}
}).start();
}
So as you can see from the code, there is a function, TCMResponse() which takes the parameters of the url which i pass, and it does web scraping, i know all these can be done using volley/ JSONParser easily. But i am just experimenting, how to parse using web scraping.
So after the page is scraped, i need that function to return the response of the scraped page,
I've used Callable with executor service, but it again freezes the thread..
Have a look on what i've done:
public static String TCMResponse(String params, final Activity act) {
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
final String url = "https://115.248.161.106/ois/API/android/" + params;
response="";
class MyBgThread implements Callable<String>
{
#Override
public String call() throws Exception {
try{
Document doc = Jsoup.connect(url).validateTLSCertificates(false).timeout(6000).get();
return doc.text();
}catch (Exception e)
{
Log.d("Exception",e.toString());
Snackbar.with(act, null)
.type(Type.ERROR)
.message("Something got wrong!")
.duration(Duration.LONG)
.show();
return "{'auth':'false'}";
}
}
}
Callable<String> worker = new MyBgThread();
ExecutorService ex = Executors.newSingleThreadExecutor();
Future<String> future = ex.submit(worker);
try{
response = future.get();
}catch(Exception e)
{
Log.d("Thread Ex",e+"");
}
ex.shutdown();
return response;
}
The main thread gets blocked because of your call to Future::get().
From the docs:
Waits if necessary for the computation to complete, and then retrieves its result.
which means; if the task Thread has not yet finished, the current Thread will wait until it returns a result.
I can see another problem in your code: you are showing a Snackbar, which is a UI component, in a Thread that is not the UI Thread.
Since you are working on Android, I would definitely use an AsyncTask, perform the expensive call in doInBackground(), then update the UI in onPostExecute().
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 am using a "transceiver" to send a request from the client to the server and wait for the response. I learned from [here][1] the way to communicate between two threads and wrote bellow codes:
public class ThreadEvent {
private Object lock;
private Object data;
private String ntfInfo;
public ThreadEvent() {
data = null;
lock = new Object();
ntfInfo = "NONE";
}
public boolean await(int time) {
synchronized (lock) {
try {
lock.wait(time);
return true;
} catch (InterruptedException ex) {
LogManager.ex(ex);
return false;
}
}
}
public void signal() {
synchronized (lock) {
ntfInfo = (new Throwable()).getStackTrace()[1].getMethodName() + "#"
+ (new Throwable()).getStackTrace()[1].getClassName() + "#"
+ "line" + (new Throwable()).getStackTrace()[1].getLineNumber() + "#"
+ (new Throwable()).getStackTrace()[1].getFileName();
lock.notify();
}
}
public synchronized void putData(Object data) {
this.data = data;
}
public synchronized Object takeData() {
Object res = data;
data = null;
return res;
}
public String takeNtfInfo() {
String info = ntfInfo;
ntfInfo = "NONE";
return info;
}
}
I found sometimes the send-and-wait thread was not always been notified by the response, nor been interrupted, (as per my understanding) but was awaked from the wait by some mysterious "thing". Here is the log:
1460717223039:DEBUG:1 starting... #<init>#wsclientapp.GUIManager#line57#GUIManager.java
1460717229475:DEBUG:2 transceive()#line30#WSTransceiver.java
1460717229735:DEBUG:3 forward()#line69#WSTransceiver.java
1460717229739:DEBUG:4 transceive(ivoked by: forward#wsclientapp.util.WSTransceiver#line73#WSTransceiver.java)#line42#WSTransceiver.java
1460717229750:DEBUG:5 transceive()#line30#WSTransceiver.java
1460717229768:DEBUG:6 forward()#line69#WSTransceiver.java
1460717229768:DEBUG:7 transceive(ivoked by: forward#wsclientapp.util.WSTransceiver#line73#WSTransceiver.java)#line42#WSTransceiver.java
1460717229770:DEBUG:8 transceive()#line30#WSTransceiver.java
1460717234771:DEBUG:9 transceive(ivoked by: NONE)#line42#WSTransceiver.java
You may see line2/3/4 is a transaction, and line5/6/7 is another transaction, but line8/9 shows the problem. If the transceive was awaked by someone, it should print the name of the thread, or if it's been interrupted, it should print the exception stack by the LogManager.ex(ex). But it didn't. What I did wrong?
When you call notify() only a thread which is waiting will be notified. If the threads are doing something else, the notify is lost.
When you call wait() it can wake spuriously.
In short;
only notify after a state change.
only wait in a while loop where you check that state check before waiting.
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.
I've got an app with several screens. In addition, I have a globally-running timer that occasionally (every minute or so) attempts to refresh their transaction data from a website and store it in a JSONArray (static JSONArray jTransactions).
When you go to the Transaction screen, the first thing it does is populate a ListView with the contents of jTransactions, and it will refresh the displayed info every few seconds. However if the web-thread is currently running, I get null values for everything.
I've got enough coder savvy to know that it's a threading issue, but I'm not experienced enough with JAVA/Android development to know how to handle it. And my Google-fu may be weak but the only answers I found either didn't apply or involved heavy rewriting.
I guess my question is this - how can I alter my code so that there's no direct collision between my activity and the fetch thread?
Also I fully accept that my code is probably ugly; as I said, I'm still learning the platform.
Here's a pared-down version of the thread I'm running:
static int iRefreshTransactions = 30000;
static boolean bRefreshingTransactions = false;
static Calendar cLastRefreshTransactions = null;
final Runnable mRefreshTransactions = new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
Thread T = new tRefreshTransactions();
T.start();
}
};
private class tRefreshTransactions extends Thread {
#Override
public void run() {
bRefreshingTransactions = true;
RetrieveTransactions();
bRefreshingTransactions = false;
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
cLastRefreshTransactions = Calendar.getInstance();
ShowToast("cLastRefreshTransactions(): " + cLastRefreshTransactions.getTime().toLocaleString());
mHandler.postDelayed(mRefreshTransactions, iRefreshTransactions);
}
};
private Handler failhandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// handle the failure somehow
}
};
}
Here's a pared-down version of the RetrieveTransactions() code:
// Retrieve the user's latest transactions from the website.
public boolean RetrieveTransactions() {
String result;
FailureReason = "";
iTransactions = 0;
// Retrieve the Page.
result = GetPage(Url);
// Strip the transactions from the page and convert them to a JSONArray.
try {
String sTransactions = textExtract(result, "var dataTable1Data=", ";\n", 0);
jTransactions = new JSONArray(sTransactions);
iTransactions = jTransactions.length();
return true;
} catch (JSONException e1) {
// Generally if it fails during this, there was no JSONArray to parse (hence no transactions).
FailureReason = "No Transactions Found";
return false;
}
}
And finally here's the pared-down code that displays the transactions in a listview, which is called at activity launch and every 5 seconds or so thereafter:
public void ShowTransactions() {
try {
if (!bRefreshingTransactions) {
if (iTransactions==0) {
return;
}
if (iTransactions==0) return;
List<String> listContents = new ArrayList<String>(iTransactions);
for (int i = 0; i < iTransactions; i++) {
listContents.add(jTransactions.getString(iTransactions - i - 1));
}
lvRecentTransactions.setAdapter(new ArrayAdapterTransactions(MyContext, listContents));
}
} catch (Exception e) {
// Do error stuff here
}
}
Thank you in advance. :)
It seems to be mutual exclusion problem. Make jTransaction synchronized or put the jTransaction variable in synchonized block.
synchronized(jTransactions ){
String sTransactions = textExtract(result, "var dataTable1Data=", ";\n", 0);
jTransactions = new JSONArray(sTransactions);
iTransactions = jTransactions.length();
}
I didn't test the code but I hope synchronization will help you.