Pergunta

Ao usar uma conexão de banco de dados de segmento local, é necessário encerramento da conexão quando existe o fio.

Esta Eu só posso fazer se eu posso substituir o método run () do segmento de chamada. Mesmo que não seja uma grande solução, uma vez que no momento da saída, eu não sei se uma conexão já foi aberto por esse segmento.

O problema é na verdade mais geral:. Como forçar um segmento para chamar algum método finalização de um objeto de segmento local quando ele sai

Eu olhei para as fontes de java 1.5 e descobriu que o mapa local thread é definido como nulo, o que acabará por causa da coleta de lixo para chamar finalize () , mas eu não quero contar com o coletor de lixo.

A seguir substituição parece inevitável para se certificar de que a conexão com o banco está fechado:

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

em que de libertação () fecha a conexão da base de dados, se o mesmo foi aberto. Mas não sabemos se o segmento já tenha usado este segmento local. Se get () nunca foi chamado por esta discussão, então há um grande desperdício de esforço aqui: ThreadLocal.initialValue () será chamado, um mapa será criado sobre este tópico, etc

-

Além disso esclarecimento e exemplo de acordo com o comentário de Thorbjørn:

java.lang.ThreadLocal é um tipo de fábrica para um objeto que está vinculado a um fio. Este tipo tem um absorvente para o objecto e um método de fabricação (tipicamente escrito pelo utilizador). Quando o getter é chamado ele chama o método de fábrica somente se ele nunca foi chamado antes por este segmento.

Usando ThreadLocal permite que um desenvolvedor para vincular um recurso a um fio, nem se o código de segmento foi escrito por um terceiro.

Exemplo: Digamos que temos um tipo de recurso chamado MyType e queremos ter uma e apenas um dele por thread.

Definir na classe usando: private static ThreadLocal resourceFactory = new ThreadLocal () { @sobrepor protegido MyType initialValue () { retornar nova MyType (); } }

Use no contexto local nesta classe: someMethod public void () { recurso MyType = resourceFactory.get (); resource.useResource (); }

get () pode chamar initialValue () apenas uma vez no ciclo de vida do segmento de chamada. Nesse ponto, uma instância de MyType é instanciado e obrigado a esta discussão. As chamadas subseqüentes a get () por esta discussão se referir novamente a este objeto.

O exemplo de uso clássico é quando o MyType é algum thread-inseguro text / data / formatador XML.

Mas tais formatadores geralmente não precisam ser liberada ou fechada, conexões de banco de dados fazer e eu estou usando java.lang.ThreadLocal para ter uma conexão de um banco de dados por thread.

A forma como eu vejo, java.lang.ThreadLocal é quase perfeito para isso. Quase, porque não há nenhuma maneira de fechamento garantia do recurso se o segmento de chamada pertence a um aplicativo de terceiros.

Eu preciso de seus cérebros escudeiros: Ao estender java.lang.ThreadLocal eu consegui ligar uma conexão de banco de dados para cada segmento, para ele é de uso exclusivo - incluindo tópicos que não posso modificar ou substituir. Eu consegui ter certeza de que as conexões são fechadas no caso das matrizes de rosca na exceção não capturada.

No caso de uma saída normal de discussão, o colector de lixo fecha a conexão (porque MyType substitui a finalize () ). Na realidade, isso acontece muito rapidamente, mas isso não é o ideal.

Se eu tivesse meu caminho, não teria havido outro método no java.lang.ThreadLocal :

protected void release() throws Throwable {}

Se este método existia no java.lang.ThreadLocal , chamado por JVM em qualquer saída de rosca / morte, então na minha própria substituição do que eu poderia fechar minha conexão (e o redentor teria vindo a Sião).

Na ausência de tal método, eu estou procurando uma outra maneira de fechamento confirmar. Uma maneira que não vai contar com a JVM lixo ccoleção. Agradecimentos

Foi útil?

Solução

Se você é de uma disposição sensível, desviar o olhar agora.

Eu não esperaria que isso escala muito bem; ele efetivamente dobra o número de threads no sistema. Pode haver alguns casos de uso onde é aceitável.

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();
  }
}

tratamento de erros melhor e assim por diante é deixada como um exercício para o implementador.

Você também pode ter um olhar para rastrear os tópicos / recursos em um ConcurrentHashMap com outra sondagem fio isAlive . Mas essa solução é o último recurso dos desesperados -. Objetos provavelmente vai acabar sendo verificado muitas vezes ou muito raramente

Eu não consigo pensar em outra coisa que não envolve instrumentação. AOP pode funcionar.

O pool de conexões seria minha opção preferida.

Outras dicas

Envolva seu Runnable com uma nova Runnable com um

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

construção, e deixar que seja executado em seu lugar.

Você mesmo pode fazê-lo em um método, ex:

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

e chamar esse método passando o executável que você está procurando.

Você também pode querer considerar o uso de um Executor vez. Torna muito mais fácil de gerir Runable e Callables.

Se você não usar um ExecutorService, você pode usá-lo como executor.submit(closingRunnable(normalRunnable))

Se você sabe que você estará fechando toda a sua ExecutorService e quer conexões para fechar nesse ponto, você pode definir uma fábrica de discussão que também faz o próximo "depois de todas as tarefas são feitas e desligamento convidou o executor", exemplo:

  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;
  }

Em termos de se ou não doMandatoryStuff pode saber se ou não a conexão já foi aberto ou não previamente, uma coisa que vem à mente é ter um segundo ThreadLocal que apenas faixas se ele foi aberto ou não (ex: quando a conexão é aberto, se, em seguida, definir um AtomicInteger a 2, em tempo de limpeza, verificar para ver se ele ainda está no seu padrão, digamos, 1 ...)

A prática normal JDBC é que você fechar o Connection (e Statement e ResultSet) no mesmo bloco método como você tinha adquirido-lo.

No código:

Connection connection = null;

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

Tendo isso em mente, a sua pergunta me faz pensar que há algo errado em seu design. Aquisição e fechar esse tipo de recursos caros e externos no âmbito mais curto vai salvar a aplicação de potenciais vazamentos de recursos e falhas.

Se a sua intenção original era para melhorar a conexão performance, então você precisa dar uma olhada em o pool de conexões . Você pode usar, por exemplo, o C3P0 API para isso. Ou se é um webapplication, utilizar as instalações de conexão embutido agrupamento do AppServer no sabor de um DataSource. Consulte a documentação específica appserver para mais detalhes.

Eu realmente não entendo por que você não está usando o pool de conexão tradicional. Mas vou assumir que tem as suas razões.

Quanta liberdade você tem? Como algumas estruturas DI fazer apoio ciclos de vida do objeto e variáveis ??com escopo de thread (todos muito bem proxy). você poderia usar um deles? Acho Primavera faria isso tudo para fora da caixa, enquanto Guice seria necessário um terceiro lib partido para ciclos de vida punho e âmbitos de discussão.

A seguir quanto controle você tem em ambos a criação da variável ThreadLocal ou a criação de tópicos? Eu estou supondo que você tem o controle completo sobre a ThreadLocal mas limitado a nenhum sobre a criação de tópicos?

Você poderia usar a Aspectos programação orientada para monitorar a nova Runnable ou Threads estendendo o método run () para incluir a limpeza? Você também vai precisar para estender a ThreadLocal para que ele possa se registrar.

Você tinha que abrir a conexão uma vez, então você também tem que lidar com o fechamento no mesmo lugar. Dependendo do seu ambiente os fios podem ser reutilizados e você não pode esperar que o segmento a ser lixo coletado antes do encerramento da aplicação.

Eu acho que no caso geral não há nenhuma boa solução para isso, além do clássico:. O código que recebe o recurso tem que ser responsável por fechá-lo

No caso específico, se você está chamando tópicos a este grau você poderia passar na conexão com seus métodos no início da rosca, ou com um método que leva um parâmetro personalizado ou através de alguma forma de Dependency Injection. Então desde que você tem o código que fornece a conexão, você tem o código que remove-lo.

A injeção de dependência com base em anotações pode trabalhar aqui, como código que não requer a conexão não terá um e, portanto, não precisam ser fechados, mas parece que seu projeto é longe demais para retrofit algo assim.

Substitua o método get () em ThreaedLocal para que ele define uma propriedade Lista na subclasse. Esta propriedade pode ser facilmente consultado para determinar se o método get () tinha sido chamado para um segmento específico. Você poderia, então, acessar o ThreadLocal para limpá-lo nesse caso.

Atualizado em resposta ao comentário

O que fizemos foi

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

Basicamente apenas sempre (possivelmente aberto e depois) fechá-lo para todos os caminhos através da rosca. Em caso de ajuda ninguém lá fora:)

Eu estou olhando para o mesmo problema. Olha como até agora você tem que usar finalize (), embora seja agora obsoleto. Como as tarefas são submetidos a algum Executor, você nunca sabe quando um segmento exatamente saídas, a menos que os shows do executor você, isso significa que você tem o controle do Executor, de certa forma.

Por exemplo, se você construir o Executor, estendendo ThreadPoolExecutor, você pode substituir o afterExecution () e os terminados () métodos para realizá-lo. O antigo para um fio que sai anormalmente enquanto o último para normalmente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top