javaretry
㈠ java怎樣實現ping的功能...
可以用InetAddress的isReachable方法:
import java.net.InetAddress;
public class MainTest {
public static void main(String[] args) {
try {
int timeOut = 3000;
byte[] ip = new byte[] { (byte) 192, (byte) 168, (byte) 100, (byte) 151 };
int retry = 4;
InetAddress address = InetAddress.getByAddress(ip);
for (int i = 0; i < retry; i++) {
if (address.isReachable(timeOut)) {
System.out.println(i + " OK");
} else {
System.out.println(i + " LOSS");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
㈡ java中用try如果catch到異常,怎麼把這個異常處理掉讓程序繼續運行
需要先將Scanner內的輸入清楚,不然就重復讀取了。簡單調用Scanner的next()方法就可以了
測試已通過
package;
importjava.util.Scanner;
publicclassRetry{
privateintmyInt;
privateScannermyScanner=newScanner(System.in);
publicintgetInt(){
try{
System.out.println("請輸入法整數");
this.myInt=this.myScanner.nextInt();
}catch(Exceptione){
System.out.println("輸入錯誤,請輸入正確的數值!!!");
this.myScanner.next();
this.getInt();
}
returnthis.myInt;
}
publicstaticvoidmain(String[]args){
Retryretry=newRetry();
System.out.println(retry.getInt());
}
}
㈢ 用java連接mongodb3報錯,不知道問題在哪
在對超過百萬條記錄的集合進行聚合操作。 DBObject match=(DBObject)JSON.parse("{$match:{logType:{'$in':[5,9]}}}"); DBObject group=(DBObject)JSON.parse("{$group:{'_id':'$domainUrl','count':{'$sum':1}}}"); AggregationOutput output = logCollection.aggregate(match,group); 偶爾會發生Read timed out 異常。 com.mongodb.MongoException$Network: Read operation to server /192.168.10.202:27017 failed on database adLogTable at com.mongodb.DBTCPConnector.innerCall(DBTCPConnector.java:253) at com.mongodb.DB.command(DB.java:261) at com.mongodb.DB.command(DB.java:243) ... Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:152) 通過多次測試,發現執行一次聚合平均時間為5s,超過5s時就會報錯! 然後查看MongoDB的配置信息: socket-timeout="5000" //5s socket-timeout的默認配置為0,也就是沒有限制。 沒有超時限制,系統出了問題也不容易發現,應該根據實際情況,給出合理的超時時間。 通過多次測試發現最長執行時間為6秒,就把超時時間設置成了10000。 socket-timeout="10000" //10s 注意:MongoDB在與Spring整合時,如果要配置多個MongDB源,只會啟用最後一個<mongo:options>配置。 應該把參數配置信息存儲在properties文件中。 <mongo:mongo host="${mongodb.ip}" id="mongo202" port="${mongodb.port}"> <mongo:options connections-per-host="200" threads-allowed-to-block-for-connection-multiplier="100" connect-timeout="1000" max-wait-time="1000" auto-connect-retry="true" socket-keep-alive="true" socket-timeout="10000" slave-ok="true" write-number="1" write-timeout="0" write-fsync="true" /> </mongo:mongo> 通過Java API獲取配置參數 DBCollection logCollection = mongoTemplate.getCollection(collName); MongoOptions mongoOptions = logCollection.getDB().getMongo().getMongoOptions(); System.out.println(mongoOptions.getSocketTimeout()); 最後一點: ConnectionTimeOut和SocketTimeOut的區別: 一次完整的請求包括三個階段: 建立連接 數據傳輸 斷開連接 如果與伺服器(這里指資料庫)請求建立連接的時間超過ConnectionTimeOut,就會拋 ConnectionTimeOutException,即伺服器連接超時,沒有在規定的時間內建立連接。 如果與伺服器連接成功,就開始數據傳輸了。 如果伺服器處理數據用時過長,超過了SocketTimeOut,就會拋出SocketTimeOutExceptin,即伺服器響應超時,伺服器沒有在規定的時間內返回給客戶端數據
㈣ Java開發中 global.properties 文件的作用是什麼
一個配置文件而已,文件本身的類型和名字沒什麼特別的,重要的是文件內容。
從文件名來看,文件里的內容應該是這個java應用的全局的一些配置/資源/屬性。
properties這種類型的文件採用鍵值對的形式存放信息,一行就是一條信息,比如:
#numberofretry
Num_Rery=5
上面這條配置中,第一行是說明,properties文件以#開頭的是注釋;第二行等號左右分別是鍵和值,鍵的大小寫隨意,可包含數字和下劃線。
java代碼中獲取這個鍵對應的值使用java.util.ResourceBundle,如:
Stringredisurl=ResourceBundle.getBundle("global").getString("Num_Rery");
再多舉一個實際應用的例子,比如一個java應用要對另外一個url地址發起請求,這個地址可以寫在java代碼中,但是有時候為了便於集中管理/閱讀,那麼我們考慮把她放到一個properties文件中,鍵是URL_Call,值就是這個url地址,在要使用的地方,用上面的那行java代碼獲取到就行了。
打完收工~~~~
㈤ java 代碼運行之後出現以下錯誤,到底神馬意思呢
第一步:通過」cd「命令切換到java類的存放路徑;
第二步:重新確認java類中的代碼編寫是否正確;
第三步:輸入」javac 類名.java「,回車,執行運行,如果不報錯說明編譯正常,如果報錯,根據錯誤修改java類代碼即可。
第四步:輸入」java 類名「進行文件運行即可。
㈥ java中 我通過jdbc插入數據進入mysql資料庫,為什麼會報錯啊,一般是1000多條以後就報錯了,求大神解釋!!
你的tomcat是6.0.18以後的版本么?6.0.18版本以後的tomcat有一個防內存泄露機制,它會強行把jdbc連接給注銷掉。如果是,建議換低版本的tomcat
㈦ JAVA中 retry關鍵用來作甚
這不是關鍵字 就是標志符 指出下面語句從哪裡開始執行 你代碼裡面有continue retry; 也就是說下面從 retry: 這里繼續執行
㈧ 怎樣用Java實現網站數據採集.txt
可以使用HttpClient讀取網頁的內容
整個過程分為六步
創建 HttpClient 的實例
2. 創建某種連接方法的實例,在這里是 GetMethod。在 GetMethod 的構造函數中傳入待連接的地址
3. 調用第一步中創建好的實例的 execute 方法來執行第二步中創建好的 method 實例
4. 讀 response
5. 釋放連接。無論執行方法是否成功,都必須釋放連接
6. 對得到後的內容進行處理
實現如下:
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
public class HttpClientTest...{
public static void main(String[] args) {
//構造HttpClient的實例
HttpClient httpClient = new HttpClient();
//創建GET方法的實例
GetMethod getMethod = new GetMethod("http://www.crazyjava.org");
//使用系統提供的默認的恢復策略
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler());
try {
//執行getMethod
int statusCode = httpClient.executeMethod(getMethod);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: "
+ getMethod.getStatusLine());
}
//讀取內容
byte[] responseBody = getMethod.getResponseBoy();
//處理內容
System.out.println(new String(responseBody));
} catch (HttpException e) {
//發生異常,可能是協議不對或者返回的內容有問題
System.out.println("Please check your provided http address!");
e.printStackTrace();
} catch (IOException e) {
//發生網路異常
e.printStackTrace();
} finally {
//釋放連接
getMethod.releaseConnection();
}
}
}
這樣得到的是頁面的源代碼,再進行處理
㈨ Java線程池中的核心線程是如何被重復利用的
Java線程池中的核心線程是如何被重復利用的?
引言
在Java開發中,經常需要創建線程去執行一些任務,實現起來也非常方便,但如果並發的線程數量很多,並且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,因為頻繁創建線程和銷毀線程需要時間。此時,我們很自然會想到使用線程池來解決這個問題。
使用線程池的好處:
降低資源消耗。java中所有的池化技術都有一個好處,就是通過復用池中的對象,降低系統資源消耗。設想一下如果我們有n多個子任務需要執行,如果我們為每個子任務都創建一個執行線程,而創建線程的過程是需要一定的系統消耗的,最後肯定會拖慢整個系統的處理速度。而通過線程池我們可以做到復用線程,任務有多個,但執行任務的線程可以通過線程池來復用,這樣減少了創建線程的開銷,系統資源利用率得到了提升。
降低管理線程的難度。多線程環境下對線程的管理是最容易出現問題的,而線程池通過框架為我們降低了管理線程的難度。我們不用再去擔心何時該銷毀線程,如何最大限度的避免多線程的資源競爭。這些事情線程池都幫我們代勞了。
提升任務處理速度。線程池中長期駐留了一定數量的活線程,當任務需要執行時,我們不必先去創建線程,線程池會自己選擇利用現有的活線程來處理任務。
- // 獲取運行狀態
- private static int runStateOf(int c) { return c & ~CAPACITY; }
- // 獲取活動線程數
- private static int workerCountOf(int c) { return c & CAPACITY; }123456
- public void execute(Runnable command) {
- if (command == null)
- throw new NullPointerException();
- int c = ctl.get();
- if (workerCountOf(c) < corePoolSize) {
- if (addWorker(command, true))
- return;
- c = ctl.get();
- }
- if (isRunning(c) && workQueue.offer(command)) {
- int recheck = ctl.get();
- if (! isRunning(recheck) && remove(command))
- reject(command);
- else if (workerCountOf(recheck) == 0)
- addWorker(null, false);
- }
- else if (!addWorker(command, false))
- reject(command);
- }
- // 為分析而簡化後的代碼
- public void execute(Runnable command) {
- int c = ctl.get();
- if (workerCountOf(c) < corePoolSize) {
- // 如果當前活動線程數小於corePoolSize,則新建一個線程放入線程池中,並把任務添加到該線程中
- if (addWorker(command, true))
- return;
- c = ctl.get();
- }
- // 如果當前活動線程數大於等於corePoolSize,則嘗試將任務放入緩存隊列
- if (workQueue.offer(command)) {
- int recheck = ctl.get();
- if (workerCountOf(recheck) == 0)
- addWorker(null, false);
- }else {
- // 緩存已滿,新建一個線程放入線程池,並把任務添加到該線程中(此時新建的線程相當於非核心線程)
- addWorker(command, false)
- }
- }22
如果 當前活動線程數 < 指定的核心線程數,則創建並啟動一個線程來執行新提交的任務(此時新建的線程相當於核心線程);
如果 當前活動線程數 >= 指定的核心線程數,且緩存隊列未滿,則將任務添加到緩存隊列中;
如果 當前活動線程數 >= 指定的核心線程數,且緩存隊列已滿,則創建並啟動一個線程來執行新提交的任務(此時新建的線程相當於非核心線程);
- private boolean addWorker(Runnable firstTask, boolean core) {
- retry:
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
- // Check if queue empty only if necessary.
- if (rs >= SHUTDOWN &&
- ! (rs == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty()))
- return false;
- for (;;) {
- int wc = workerCountOf(c);
- if (wc >= CAPACITY ||
- wc >= (core ? corePoolSize : maximumPoolSize))
- return false;
- if ((c))
- break retry;
- c = ctl.get(); // Re-read ctl
- if (runStateOf(c) != rs)
- continue retry;
- // else CAS failed e to workerCount change; retry inner loop
- }
- }
- boolean workerStarted = false;
- boolean workerAdded = false;
- Worker w = null;
- try {
- w = new Worker(firstTask);
- final Thread t = w.thread;
- if (t != null) {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- // Recheck while holding lock.
- // Back out on ThreadFactory failure or if
- // shut down before lock acquired.
- int rs = runStateOf(ctl.get());
- if (rs < SHUTDOWN ||
- (rs == SHUTDOWN && firstTask == null)) {
- if (t.isAlive()) // precheck that t is startable
- throw new IllegalThreadStateException();
- workers.add(w);
- int s = workers.size();
- if (s > largestPoolSize)
- largestPoolSize = s;
- workerAdded = true;
- }
- } finally {
- mainLock.unlock();
- }
- if (workerAdded) {
- t.start();
- workerStarted = true;
- }
- }
- } finally {
- if (! workerStarted)
- addWorkerFailed(w);
- }
- return workerStarted;
- }
- // 為分析而簡化後的代碼
- private boolean addWorker(Runnable firstTask, boolean core) {
- int wc = workerCountOf(c);
- if (wc >= (core ? corePoolSize : maximumPoolSize))
- // 如果當前活動線程數 >= 指定的核心線程數,不創建核心線程
- // 如果當前活動線程數 >= 指定的最大線程數,不創建非核心線程
- return false;
- boolean workerStarted = false;
- boolean workerAdded = false;
- Worker w = null;
- try {
- // 新建一個Worker,將要執行的任務作為參數傳進去
- w = new Worker(firstTask);
- final Thread t = w.thread;
- if (t != null) {
- workers.add(w);
- workerAdded = true;
- if (workerAdded) {
- // 啟動剛剛新建的那個worker持有的線程,等下要看看這個線程做了啥
- t.start();
- workerStarted = true;
- }
- }
- } finally {
- if (! workerStarted)
- addWorkerFailed(w);
- }
- return workerStarted;
- }2223242526272829303132
- private final class Worker
- extends AbstractQueuedSynchronizer
- implements Runnable{
- // ....
- }
- Worker(Runnable firstTask) {
- setState(-1); // inhibit interrupts until runWorker
- this.firstTask = firstTask;
- this.thread = getThreadFactory().newThread(this);
- }123456789101112
- public void run() {
- runWorker(this);
- }
- final void runWorker(Worker w) {
- Thread wt = Thread.currentThread();
- Runnable task = w.firstTask;
- w.firstTask = null;
- w.unlock(); // allow interrupts
- boolean completedAbruptly = true;
- try {
- while (task != null || (task = getTask()) != null) {
- w.lock();
- // If pool is stopping, ensure thread is interrupted;
- // if not, ensure thread is not interrupted. This
- // requires a recheck in second case to deal with
- // shutdownNow race while clearing interrupt
- if ((runStateAtLeast(ctl.get(), STOP) ||
- (Thread.interrupted() &&
- runStateAtLeast(ctl.get(), STOP))) &&
- !wt.isInterrupted())
- wt.interrupt();
- try {
- beforeExecute(wt, task);
- Throwable thrown = null;
- try {
- task.run();
- } catch (RuntimeException x) {
- thrown = x; throw x;
- } catch (Error x) {
- thrown = x; throw x;
- } catch (Throwable x) {
- thrown = x; throw new Error(x);
- } finally {
- afterExecute(task, thrown);
- }
- } finally {
- task = null;
- w.completedTasks++;
- w.unlock();
- }
- }
- completedAbruptly = false;
- } finally {
- processWorkerExit(w, completedAbruptly);
- }
- }04142434445464748
- // 為分析而簡化後的代碼
- final void runWorker(Worker w) {
- Runnable task = w.firstTask;
- w.firstTask = null;
- while (task != null || (task = getTask()) != null) {
- try {
- task.run();
- } finally {
- task = null;
- }
- }
- }12345678910111213
- private Runnable getTask() {
- boolean timedOut = false; // Did the last poll() time out?
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
- // Check if queue empty only if necessary.
- if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
- decrementWorkerCount();
- return null;
- }
- int wc = workerCountOf(c);
- // Are workers subject to culling?
- boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
- if ((wc > maximumPoolSize || (timed && timedOut))
- && (wc > 1 || workQueue.isEmpty())) {
- if ((c))
- return null;
- continue;
- }
- try {
- Runnable r = timed ?
- workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
- workQueue.take();
- if (r != null)
- return r;
- timedOut = true;
- } catch (InterruptedException retry) {
- timedOut = false;
- }
- }
- }
- // 為分析而簡化後的代碼
- private Runnable getTask() {
- boolean timedOut = false;
- for (;;) {
- int c = ctl.get();
- int wc = workerCountOf(c);
- // timed變數用於判斷是否需要進行超時控制。
- // allowCoreThreadTimeOut默認是false,也就是核心線程不允許進行超時;
- // wc > corePoolSize,表示當前線程池中的線程數量大於核心線程數量;
- // 對於超過核心線程數量的這些線程,需要進行超時控制
- boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
- if (timed && timedOut) {
- // 如果需要進行超時控制,且上次從緩存隊列中獲取任務時發生了超時,那麼嘗試將workerCount減1,即當前活動線程數減1,
- // 如果減1成功,則返回null,這就意味著runWorker()方法中的while循環會被退出,其對應的線程就要銷毀了,也就是線程池中少了一個線程了
- if ((c))
- return null;
- continue;
- }
- try {
- Runnable r = timed ?
- workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
- workQueue.take();
- // 注意workQueue中的poll()方法與take()方法的區別
- //poll方式取任務的特點是從緩存隊列中取任務,最長等待keepAliveTime的時長,取不到返回null
- //take方式取任務的特點是從緩存隊列中取任務,若隊列為空,則進入阻塞狀態,直到能取出對象為止
- if (r != null)
- return r;
- timedOut = true;
- } catch (InterruptedException retry) {
- timedOut = false;
- }
- }
- }39
如果當前活動線程數大於核心線程數,當去緩存隊列中取任務的時候,如果緩存隊列中沒任務了,則等待keepAliveTime的時長,此時還沒任務就返回null,這就意味著runWorker()方法中的while循環會被退出,其對應的線程就要銷毀了,也就是線程池中少了一個線程了。因此只要線程池中的線程數大於核心線程數就會這樣一個一個地銷毀這些多餘的線程。
如果當前活動線程數小於等於核心線程數,同樣也是去緩存隊列中取任務,但當緩存隊列中沒任務了,就會進入阻塞狀態,直到能取出任務為止,因此這個線程是處於阻塞狀態的,並不會因為緩存隊列中沒有任務了而被銷毀。這樣就保證了線程池有N個線程是活的,可以隨時處理任務,從而達到重復利用的目的。
當有新任務來的時候,先看看當前的線程數有沒有超過核心線程數,如果沒超過就直接新建一個線程來執行新的任務,如果超過了就看看緩存隊列有沒有滿,沒滿就將新任務放進緩存隊列中,滿了就新建一個線程來執行新的任務,如果線程池中的線程數已經達到了指定的最大線程數了,那就根據相應的策略拒絕任務。
當緩存隊列中的任務都執行完了的時候,線程池中的線程數如果大於核心線程數,就銷毀多出來的線程,直到線程池中的線程數等於核心線程數。此時這些線程就不會被銷毀了,它們一直處於阻塞狀態,等待新的任務到來。
很顯然,線程池一個很顯著的特徵就是「長期駐留了一定數量的活線程」,避免了頻繁創建線程和銷毀線程的開銷,那麼它是如何做到的呢?我們知道一個線程只要執行完了run()方法內的代碼,這個線程的使命就完成了,等待它的就是銷毀。既然這是個「活線程」,自然是不能很快就銷毀的。為了搞清楚這個「活線程」是如何工作的,下面通過追蹤源碼來看看能不能解開這個疑問。
分析方法
在分析源碼之前先來思考一下要怎麼去分析,源碼往往是比較復雜的,如果知識儲備不夠豐厚,很有可能會讀不下去,或者讀岔了。一般來講要時刻緊跟著自己的目標來看代碼,跟目標關系不大的代碼可以不理會它,一些異常的處理也可以暫不理會,先看正常的流程。就我們現在要分析的源碼而言,目標就是看看線程是如何被復用的。那麼對於線程池的狀態的管理以及非正常狀態下的處理代碼就可以不理會,具體來講,在ThreadPollExcutor類中,有一個欄位private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));是對線程池的運行狀態和線程池中有效線程的數量進行控制的, 它包含兩部分信息: 線程池的運行狀態 (runState) 和線程池內有效線程的數量 (workerCount),還有幾個對ctl進行計算的方法:
以上兩個方法在源碼中經常用到,結合我們的目標,對運行狀態的一些判斷及處理可以不用去管,而對當前活動線程數要加以關注等等。
下面將遵循這些原則來分析源碼。
解惑
當我們要向線程池添加一個任務時是調用ThreadPollExcutor對象的execute(Runnable command)方法來完成的,所以先來看看ThreadPollExcutor類中的execute(Runnable command)方法的源碼:
按照我們在分析方法中提到的一些原則,去掉一些相關性不強的代碼,看看核心代碼是怎樣的。
這樣一看,邏輯應該清晰很多了。
接下來看addWorker(Runnable firstTask, boolean core)方法
同樣,我們也來簡化一下:
看到這里,我們大概能猜測到,addWorker方法的功能就是新建一個線程並啟動這個線程,要執行的任務應該就是在這個線程中執行。為了證實我們的這種猜測需要再來看看Worker這個類。
從上面的Worker類的聲明可以看到,它實現了Runnable介面,以及從它的構造方法中可以知道待執行的任務賦值給了它的變數firstTask,並以它自己為參數新建了一個線程賦值給它的變數thread,那麼運行這個線程的時候其實就是執行Worker的run()方法,來看一下這個方法:
在run()方法中只調了一下 runWorker(this) 方法,再來簡化一下這個 runWorker() 方法
很明顯,runWorker()方法裡面執行了我們新建Worker對象時傳進去的待執行的任務,到這里為止貌似這個worker的run()方法就執行完了,既然執行完了那麼這個線程也就沒用了,只有等待虛擬機銷毀了。那麼回顧一下我們的目標:Java線程池中的核心線程是如何被重復利用的?好像並沒有重復利用啊,新建一個線程,執行一個任務,然後就結束了,銷毀了。沒什麼特別的啊,難道有什麼地方漏掉了,被忽略了?再仔細看一下runWorker()方法的代碼,有一個while循環,當執行完firstTask後task==null了,那麼就會執行判斷條件(task = getTask()) != null,我們假設這個條件成立的話,那麼這個線程就不止只執行一個任務了,可以執行多個任務了,也就實現了重復利用了。答案呼之欲出了,接著看getTask()方法
老規矩,簡化一下代碼來看:
從以上代碼可以看出,getTask()的作用是
小結
通過以上的分析,應該算是比較清楚地解答了「線程池中的核心線程是如何被重復利用的」這個問題,同時也對線程池的實現機制有了更進一步的理解:
注意:
本文所說的「核心線程」、「非核心線程」是一個虛擬的概念,是為了方便描述而虛擬出來的概念,在代碼中並沒有哪個線程被標記為「核心線程」或「非核心線程」,所有線程都是一樣的,只是當線程池中的線程多於指定的核心線程數量時,會將多出來的線程銷毀掉,池中只保留指定個數的線程。那些被銷毀的線程是隨機的,可能是第一個創建的線程,也可能是最後一個創建的線程,或其它時候創建的線程。一開始我以為會有一些線程被標記為「核心線程」,而其它的則是「非核心線程」,在銷毀多餘線程的時候只銷毀那些「非核心線程」,而「核心線程」不被銷毀。這種理解是錯誤的。
另外還有一個重要的介面 BlockingQueue 值得去了解,它定義了一些入隊出隊同步操作的方法,還可以阻塞,作用很大。