我有一個由後臺服務調用的Runnable。 Runnable本身在我的FactoryManagerClass中被初始化爲一個SingleTon對象。讓Runnable或Thread只調用一次
在我的Logcat中,我在同一秒內運行了一天之後有幾次連接嘗試。
06-15 12:00:52.665 9374-9656/com.myAppI/﹕ RestPushServiceRunnable: : Requesting url: http://my.ip/lp/053303932; LastModify: Thu, 01 Jan 1970 00:00:00 UTC; ETAG:
06-15 12:00:52.680 9374-17595/com.myAppI/﹕ RestPushServiceRunnable: : Requesting url: http://my.ip/lp/053303932; LastModify: Thu, 01 Jan 1970 00:00:00 UTC; ETAG:
06-15 12:00:52.685 9374-15696/com.myAppI/﹕ RestPushServiceRunnable: : Requesting url: http://my.ip/lp/053303932; LastModify: Thu, 01 Jan 1970 00:00:00 UTC; ETAG:
這意味着它創建了3次,但至少它應該只有1次可運行的運行。
private static LPRunnable lpRunnable = null;
private static ExecutorService pushThreadPoolExecutor = null;
public static LPRunnable getLPRunnable() {
if (lpRunnable == null) {
synchronized (LPRunnable.class) {
lpRunnable = new LPRunnable (CustomService.getContext());
}
}
return lpRunnable;
}
public static ExecutorService getPushThreadPoolExecutor() {
if (pushThreadPoolExecutor == null) {
pushThreadPoolExecutor = Executors.newSingleThreadExecutor();
}
return pushThreadPoolExecutor;
}
我運行的類是(幾乎截斷)
public class LPRunnable implements Runnable {
public static boolean isRunning = false;
@Override
public void run() {
HttpURLConnection connection = null;
try {
isRunning = true;
URL serverAddress;
while (isRunning) {
try {
MDatabaseManager databaseManager = methodToInitMYDBManager();
PushConnection pushConnection = new PushConnection();
pushConnection.setStatusCode(0);
//this is used to store the last connection attempt (time)
databaseManager.insertEntry(toContentValues(pushConnection), "pc");
connection = null;
serverAddress = new URL(myURLforLongPolling);
connection = (HttpURLConnection) serverAddress.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(false);
connection.setReadTimeout(100000);
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Content-Transfer-Encoding", "binary");
connection.connect();
long begin_time = System.currentTimeMillis();
int resCode = connection.getResponseCode();
if (resCode != 200) {
throw new IOException("Response Status Code not 200");
}
parseInputstream(connection.getInputStream());
long end_time = System.currentTimeMillis();
} catch (Exception e) {
e.printStackTrace();
isRunning = false;
} finally {
if (connection != null) {
connection.disconnect();
connection = null;
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
isRunning = false;
}
}
現在最有趣的部分。我有一個AlarmTimer調用另一個Runnable。 Runnable做了一些事情,最後通過調用這個方法來驗證連接。
Future connectionFuture;
public void validatePushConnection() {
databaseManager = myMethodToInitTheDb();
//here it will get the last sent push
PushConnection pushConnection = databaseManager.getLastPushConnectionFromDB();
if (pushConnection != null) {
long secondsSinceLastPush = ((System.currentTimeMillis() - pushConnection.getLast_connection_attempt().getTime())/1000);
if ((secondsSinceLastPush >= 400 || secondsSinceLastPush == 0) && hasInternet()) {
Log.e("CommandManager", "Delay is larger then 400 or and internet is there. Reconnecting");
mFactoryManager.getLPRunnable().isRunning = false;
connectionFuture = mFactoryManager.getPushThreadPoolExecutor().submit(mFactoryManager.getLPRunnable());
}
} else {
Log.d("CommandManager", "No push yet. Waiting for the first push");
if (connectionFuture == null || connectionFuture.isCancelled() || connectionFuture.isDone() || connectionFuture.get() == null) {
connectionFuture = mFactoryManager.getPushThreadPoolExecutor().submit(mFactoryMAnager.getLPRunnable());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
的問題是,該連接(可運行)的服務器似乎被創建多次(經過一段時間),並只應具有的可運行一個實例。什麼可能導致多重連接?
謝謝,但我完全不明白。你是什麼意思,它沒有任何意義?我認爲同步將確保它只被稱爲onec?訪問的正確方式是什麼,確保它只有一個實例而不將其加載到內存中(延遲加載)?我更喜歡在擴展中不初始化應用 –
第一個線程來到if子句並開始創建單例實例。同時第二個線程來到相同的if子句,並且還開始創建單例,因爲第一個線程尚未完成創建它。因此,您需要鎖定/同步,並檢查進入同步塊之前和之後的情況。 – Matthias
謝謝。我已經把它解決了,但是你能否在你的示例中解釋一下: 如果你說「不那麼安全」。什麼是同步用於?我認爲它會鎖定綁定到在同步塊中使用的類?是不是像你發佈的第二個例子一樣?由於Thread和Runnable也是以SingleTon方式加載的,因此不應該有兩個Runnable實例,不應該嗎?有沒有更好的方法做到這一點? –