private synchronized boolean ensureWaitingThread() { if (mThreadCount <= mServicingCount) { try { // Only wait if no threads. Otherwise the lock on this object // will prevent threads from entering the exitThread method. startThread(mThreadCount == 0); } catch (NoThreadException e) { if (!e.isThreadPoolClosed()) { if (mThreadCount == 0) { uncaughtException(e); return false; } } } catch (InterruptedException e) { return false; } catch (Throwable e) { uncaughtException(e); return false; } } return true; }
public void run() { boolean forceExit = false; TransactionQueueEvent event; while (true) { try { // allow event to be GC'd in case we wait() on next event event = null; // Phase 1: wait for a transaction try { if ((event = nextTransactionEvent()) == null) { // Go into idle mode. continue; } } catch (InterruptedException e) { forceExit = true; continue; } long enqueueTimestamp = event.getTimestampMillis(); // Phase 2: spawn off a replacement thread try { startThread(false); } catch (NoThreadException e) { if (e.isThreadPoolClosed()) { forceExit = true; // Don't "continue" because the transaction must // still be serviced first. } } catch (InterruptedException e) { forceExit = true; // Don't "continue" because the transaction must // still be serviced first. } catch (Throwable e) { uncaughtException(e); } finally { // Only indicate that transaction has been dequeued // after a replacement thread has been created. // Queue time is more accurate this way because time // spent waiting for a thread is time spent not being // serviced. try { event = transactionDequeued(event); } catch (Throwable e) { uncaughtException(e); } } long serviceTimestamp = event.getTimestampMillis(); // Phase 3: service the transaction long timeout = getTransactionTimeout(); if (timeout >= 0 && (serviceTimestamp - enqueueTimestamp) >= timeout) { try { event.getTransaction().cancel(); } finally { transactionExpired(event); } } else { try { event.getTransaction().service(); transactionServiced(event); } catch (Throwable e) { uncaughtException(e); try { event.getTransaction().cancel(); } catch (Throwable e2) { uncaughtException(e2); } transactionException(event, e); } } } catch (Throwable e) { try { uncaughtException(e); } catch (Throwable e2) { // If another error is thrown while trying to log the // first error, ignore it. This ensures that the // exitThread method is called, even if // OutOfMemoryErrors are being thrown around. } } finally { if (exitThread(forceExit)) { break; } } } }