Domanda

Quando si Utilizza un filo-connessione al database locale, la chiusura della connessione è necessaria quando il thread esiste.

Questo lo posso fare solo se posso sovrascrivere il metodo run() del thread chiamante.Anche questo non è una grande soluzione, dato che al momento dell'uscita, non so se la connessione è mai stato aperto da quel thread.

Il problema è più generale:Come forzare un thread per chiamare alcuni finalizzazione metodo di un thread-oggetto locale quando esce.

Ho guardato i sorgenti di java 1.5 e trovato che il thread mappa locale è impostato su null, che alla fine causano la procedura di garbage collection chiamata finalize(), ma non voglio contare il garbage collector.

I seguenti ignorare sembra inevitabile, per assicurarsi che la connessione al database è chiuso:

@Override 
public void remove() {
    get().release(); 
    super.remove(); 
}

dove release() chiude la connessione al database, se è stato aperto.Ma non sappiamo se il thread ha mai usato questo thread locale.Se get() non è mai stato chiamato da questo thread, quindi non c'è abbastanza uno spreco di sforzo qui: ThreadLocal.initialValue() sarà chiamato, è una mappa che verrà creato su questo thread, etc.

-

Ulteriori chiarimenti e con l'esempio come per Thorbjørn commento:

java.lang.ThreadLocal è un tipo di fabbrica per un oggetto che è legato a un filo.Questo tipo ha un getter per l'oggetto e un metodo factory (in genere scritti dall'utente).Quando il getter si chiama, chiama il metodo factory solo se non è stato mai chiamato prima da questo thread.

Utilizzando ThreadLocal consente agli sviluppatori di associare una risorsa per un thread, anche se il codice del thread è stato scritto da una terza parte.

Esempio:Supponiamo di avere un Tipo di risorsa chiamato MyType e vogliamo avere un unico thread.

Definire nella classe:private static ThreadLocal resourceFactory = new ThreadLocal(){ @override protetto MyType initialValue(){ return new MyType();} }

Utilizzare nel contesto locale in questa classe:public void someMethod(){ MyType resource = resourceFactory.get();risorsa.useResource();}

get() può chiamare initialValue() solo una volta nel ciclo di vita del thread chiamante.A quel punto un'istanza di MyType viene creata e legato a questo thread.Le chiamate successive a get() da questo thread facendo ancora riferimento a questo oggetto.

Il classico esempio di utilizzo è quando MyType è un thread suscettibili di testo/data/xml formatter.

Ma tale formattatori di solito non hanno bisogno di essere rilasciato o chiuso, le connessioni al database fare e sto usando java.lang.ThreadLocal per avere una connessione al database per ogni thread.

Il mio modo di vedere, java.lang.ThreadLocal è quasi l'ideale.Quasi perché non c'è alcun modo per garantire la chiusura della risorsa, se il thread chiamante appartiene a un'applicazione di terze parti.

Ho bisogno del vostro cervello squires:Estendendo java.lang.ThreadLocal Sono riuscito a legare una connessione al database per ogni thread, per l'esclusivo utilizzo, comprese le discussioni che non riesco a modificare o sostituire.Ho gestito per assicurarsi che le connessioni chiuse nel caso in cui il thread muore uncaught exception.

In caso di normale filo di uscita, il garbage collector chiude la connessione (perché MyType sostituisce il finalize()).In realtà succede tutto in fretta, ma questo non è l'ideale.

Se fosse per me, ci sarebbe stato un altro metodo java.lang.ThreadLocal:

protected void release() throws Throwable {}

Se questo metodo esisteva java.lang.ThreadLocal, chiamato dalla JVM su qualsiasi filo di uscita/morte, quindi nel mio override di essa ho potuto chiudere la mia connessione (e redentore sarebbe venuto a Sion).

In assenza di tale metodo, sto cercando un altro modo per confermare la chiusura.Un modo che non si basano su JVM di garbage collection.

Grazie

È stato utile?

Soluzione

Se siete sensibili disposizione, non guardare ora.

Non mi aspetto che scala molto bene;effettivamente raddoppia il numero di thread nel sistema.Ci possono essere alcune situazioni in cui è accettabile.

public class Estragon {
  public static class Vladimir {
    Vladimir() { System.out.println("Open"); }
    public void close() { System.out.println("Close");}
  }

  private static ThreadLocal<Vladimir> HOLDER = new ThreadLocal<Vladimir>() {
    @Override protected Vladimir initialValue() {
      return createResource();
    }
  };

  private static Vladimir createResource() {
    final Vladimir resource = new Vladimir();
    final Thread godot = Thread.currentThread();
    new Thread() {
      @Override public void run() {
        try {
          godot.join();
        } catch (InterruptedException e) {
          // thread dying; ignore
        } finally {
          resource.close();
        }
      }
    }.start();
    return resource;
  }

  public static Vladimir getResource() {
    return HOLDER.get();
  }
}

Migliore gestione degli errori e così via è lasciato come esercizio per il realizzatore.

Si potrebbe anche dare un'occhiata a seguire il thread/risorse in un ConcurrentHashMap con un altro filo di polling isAlive.Ma che soluzione è l'ultima risorsa dei disperati - oggetti sarà probabilmente finiscono per essere controllato troppo spesso o troppo raramente.

Io non riesco a pensare a niente altro che non prevede l'utilizzo di strumentazione.AOP potrebbe funzionare.

Il pool di connessioni sarebbe la mia opzione preferita.

Altri suggerimenti

Avvolgere il vostro Eseguibile con un nuovo Eseguibile con un

try {
  wrappedRunnable.run();
} finally {
  doMandatoryStuff();
}

costruzione, e lasciate CHE invece eseguito.

Si potrebbe anche fare in un metodo, ex:

  Runnable closingRunnable(Runnable wrappedRunnable) {
    return new Runnable() {
      @Override
      public void run() {
        try {
          wrappedRunnable.run();
        } finally {
          doMandatoryStuff();
        }
      }
    };
  }

e chiamare il metodo passando l'eseguibile che stai cercando.

Si potrebbe anche voler considerare l'utilizzo di un Esecutore, invece.Rende molto più facile da gestire Runable e Callable.

Se si utilizza un ExecutorService, si può usare come executor.submit(closingRunnable(normalRunnable))

Se sai che sarai l'arresto del tutto ExecutorService e desidera connessioni per chiudere a questo punto, è possibile impostare un filo di fabbrica che fa anche il vicino "dopo tutte le attività sono fatto e di arresto chiamato l'esecutore", esempio:

  ExecutorService autoClosingThreadPool(int numThreads) {
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); // same as Executors.newFixedThreadPool
    threadPool.setThreadFactory(new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
        return new Thread(closingRunnable(r)); // closes it when executor is shutdown
      }
    });
    return threadPool;
  }

In termini di se o non doMandatoryStuff può sapere se la connessione è mai stato aperto o meno in precedenza, una cosa che mi viene in mente è di avere un secondo ThreadLocal che solo tracce se è stato aperto o no (es:quando la connessione è aperta, ottenere quindi impostare un AtomicInteger a 2, in tempi di pulizia, controllare per vedere se è ancora al suo default, diciamo, 1...)

Il normale JDBC pratica è che si chiude il Connection (e Statement e ResultSet), e nel metodo stesso blocco come ti ha acquisito.

Nel codice:

Connection connection = null;

try {
    connection = getConnectionSomehow();
    // Do stuff.
} finally {
    if (connection != null) {
        try {
            connection.close();
        } catch (SQLException e) {
            ignoreOrLogItButDontThrowIt(e);
        }
    }
}

Tenendo questo in mente, la tua domanda mi fa pensare che c'è qualcosa di sbagliato nel vostro disegno.L'acquisizione e la chiusura di quei costosi e risorse esterne in breve il campo di applicazione si salva l'applicazione da parte di potenziali perdite di risorse e si blocca.

Se il tuo intento originale era quello di migliorare il collegamento di prestazioni, allora avete bisogno di prendere uno sguardo per il pool di connessioni.Si può utilizzare ad esempio il C3P0 API per questo.O se è una webapplication, utilizzare il appserver incorporato il pool di connessioni strutture in sapore di un DataSource.Consultare il appserver documentazione specifica per i dettagli.

Io non capisco perché non si utilizza il tradizionale pool di connessioni.Ma devo presumere tu hai le tue ragioni.

Quanta libertà hai?Come alcuni DI quadri di assistenza oggetto cicli di vita e filo-scope variabili (tutte ben proxy).Si potrebbe utilizzare uno di loro?Penso che la Primavera avrebbe fatto tutto questo, fuori dalla scatola, mentre Guice avrebbe bisogno di un 3rd party lib per gestire i cicli di vita del thread ambiti.

Accanto quanto controllo hai sulla creazione di ThreadLocal variabile o la creazione di thread?Sto indovinando che si ha il controllo completo sul ThreadLocal ma limitato a nessuno sulla creazione di thread?

Si può usare un Aspect-oriented programming per monitorare new Runnable o Thread di estendere il metodo run() di includere la pulizia?Sarà inoltre necessario per estendere la ThreadLocal modo che si possa registrare.

Si doveva aprire la connessione una volta, in modo che anche per gestire la chiusura nello stesso luogo.A seconda dell'ambiente, il thread può essere riutilizzato e non si può pretendere che il thread di immondizia raccolti prima della chiusura dell'applicazione.

Penso che in generale non c'è una buona soluzione per questo, altro che il classico:Il codice che ottiene la risorsa deve essere responsabile per la chiusura.

Nel caso specifico, se si chiama thread a questo punto si potrebbe passare una connessione con i vostri metodi all'inizio del thread, con un metodo che accetta un parametro personalizzato o mediante qualche forma di Iniezione di Dipendenza.Poi visto che hai il codice che fornisce la connessione, si ha il codice che rimuove.

Una Iniezione di Dipendenza basato su annotazioni potrebbe funzionare qui, come di codice che non richiedono la connessione non si ottiene uno e quindi non avrebbe bisogno di essere chiuso, ma suona come il vostro disegno è troppo lungo per il retrofit qualcosa di simile.

L'Override del metodo get() in ThreaedLocal così che si stabilisce un Elenco di proprietà all'interno della sottoclasse.Questa proprietà può essere facilmente eseguita per determinare se il metodo get() era stato chiamato per un determinato thread.È quindi possibile accedere al ThreadLocal pulire in quel caso.

Aggiornato in risposta al commento

Quello che abbiamo fatto è stato

@Override
public void run() {
  try {
    // ...
  } finally {
    resource.close();
  }
}

Fondamentalmente sempre (forse aprire e poi di chiuderlo per tutti i percorsi attraverso il filo.Nel caso In cui aiuta qualcuno là fuori :)

Sto guardando lo stesso problema.Sembra così lontano è necessario utilizzare finalize(), ma ormai è obsoleto.I compiti sono presentate alcune Esecutore, non si può mai sapere quando un thread esattamente uscite, a meno che l'Esecutore mostra, il che significa che si ha il controllo di Esecutore per estendere alcune.

Per esempio, se si crea l'Esecutore estendendo ThreadPoolExecutor, si potrebbe ignorare il afterExecution() e terminata() metodi per realizzarlo.Il primo per un filo in uscita in modo anomalo mentre il secondo normalmente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top