Aplicação multi-thread

Tenho uma aplicação que usa threads e para fazer alguns controles eu uso Vector e analisando a mesma vi que muitas threads entram em wait ou ficam em blocked.
Seria o vector que poderia estar causando isso?
Abaixo segue o um stackTrace quando a thread está em blocked:

ava.net.SocketInputStream.socketRead0 ( native code ) java.net.SocketInputStream.read ( unknown source ) sun.nio.cs.StreamDecoder.readBytes ( unknown source ) sun.nio.cs.StreamDecoder.implRead ( unknown source ) sun.nio.cs.StreamDecoder.read ( unknown source ) java.io.InputStreamReader.read ( unknown source ) java.io.BufferedReader.fill ( unknown source ) java.io.BufferedReader.readLine ( unknown source ) java.io.BufferedReader.readLine ( unknown source ) http.Request.setResultServer ( Request.java:50 ) http.Request.sendByGET ( Request.java:199 ) client.http.ClientSDPRequest.send ( ClientSDPRequest.java:117 ) client.http.ClientSDPRequest.reserveAndCommit ( ClientSDPRequest.java:141 ) billing.request.RequestSDPThread.run ( RequestSDPThread.java:153 ) java.util.concurrent.ThreadPoolExecutor$Worker.runTask ( unknown source ) java.util.concurrent.ThreadPoolExecutor$Worker.run ( unknown source ) java.lang.Thread.run ( unknown source )

Outro stackTrace, esse eu acredito que seja causado pelo log4j eu já aumentei o nível do log, melhorou bastante, mas ainda aparece este blocked:

org.apache.log4j.Category.callAppenders ( Category.java:204 ) org.apache.log4j.Category.forcedLog ( Category.java:391 ) org.apache.log4j.Category.info ( Category.java:666 ) billing.control.BillingThread.run ( BillingThread.java:163 ) java.util.concurrent.ThreadPoolExecutor$Worker.runTask ( unknown source ) java.util.concurrent.ThreadPoolExecutor$Worker.run ( unknown source ) java.lang.Thread.run ( unknown source )

Agora abaixo segue um stackTrace quando a thread está em wait:

java.net.SocketInputStream.socketRead0 ( native code ) java.net.SocketInputStream.read ( unknown source ) sun.nio.cs.StreamDecoder.readBytes ( unknown source ) sun.nio.cs.StreamDecoder.implRead ( unknown source ) sun.nio.cs.StreamDecoder.read ( unknown source ) java.io.InputStreamReader.read ( unknown source ) java.io.BufferedReader.fill ( unknown source ) java.io.BufferedReader.readLine ( unknown source ) java.io.BufferedReader.readLine ( unknown source ) http.Request.setResultServer ( Request.java:50 ) http.Request.sendByGET ( Request.java:199 ) client.http.ClientSDPRequest.send ( ClientSDPRequest.java:117 ) client.http.ClientSDPRequest.reserveAndCommit ( ClientSDPRequest.java:141 ) request.RequestSDPThread.run ( RequestSDPThread.java:153 ) java.util.concurrent.ThreadPoolExecutor$Worker.runTask ( unknown source ) java.util.concurrent.ThreadPoolExecutor$Worker.run ( unknown source ) java.lang.Thread.run ( unknown source )

Sim o java.util.Vector é sincronizado, vc realmente precisa de multi-threads?

Poste as áreas em que as threads acessam concorrentemente, e como você está fazendo para sincroniza-las.

Outra coisa. É normal threads ficarem em wait ao chamar o método read. Sua thread que faz write está com problemas?

Vou tentar colocar algumas partes do código e explicar como funciona esta parte da aplicação que usa o vector, porque o tem bastante código e iria ficar meio confuso se postasse aqui.
A parte aonde eu uso vector é aonde eu controlo o número de threads que podem ser usadas. A aplicação vai no banco retorna 500 registros e ai esses registros viram threads. As threads processam os registros do banco e quando acaba o processo ela retira do vector o registro que ela processou.
Abaixo seguem alguns trechos do código:

Thread que pega os registro do banco e coloca no vector:

[code]
while( true ) {

    	if(!this.customerDAO.getRemainingCustomersCountByChannel(this.getRuleChannel().getIdChannel())){
    		break;
    	}
    	
        nowTime = Calendar.getInstance();

        if( nowTime.after( endTime ) ) {
            break;
        } else {
            bufferThread.setCapacity( this.getLimit() );
            bufferSize = bufferThread.size();
            remainingCapacity = bufferThread.remainingCapacity();


            if( bufferSize >= this.getLimit() ) {
                continue;
            }

            if(this.isRetry()){
            	customers = this.customerDAO.getCustomersRetryForBilling( this.getRuleChannel().getIdChannel(), remainingCapacity );
            } else if (!this.isRetry()){
            	customers = this.customerDAO.getCustomersForBilling( this.getRuleChannel().getIdChannel(), remainingCapacity );
            }

            if( customers == null || customers.isEmpty() ) {
                LOGGER.debug( token + "There aren't customers to channel " + this.getRuleChannel().getIdChannel() );
                continue;
            }

            // Setando o vector, porque eh ele quem controla a quantidade de threads que eu posso criar por interacao.
            bufferThread.addAll(customers);

            newCustomers = customers.size();

            LOGGER.info( this.token +  "Total customers to be charged: " + newCustomers );

            Iterator<CustomerRelationChannel> iterator = customers.iterator();
            while(iterator.hasNext()){
                try {
                    customer = bufferThread.next();
                    requestSDPThread = new RequestSDPThread();
                    requestSDPThread.setApplicationContext( applicationContext );
                    requestSDPThread.setToken( this.getToken() );
                    if( this.isRetry() ) {
                        requestSDPThread.setRetry( 1 );
                    } else {
                        requestSDPThread.setRetry( 0 );
                    }
                    requestSDPThread.setCustomer( iterator.next() );
                    requestSDPThread.setRuleChannel( this.getRuleChannel() );
                    requestSDPThread.setBuffer( bufferThread );

                    //Thread que "dispara" as threads de request
                    ThreadControl.EXECUTOR_SERVICE.execute( requestSDPThread );
                } catch(Exception e) {
                    LOGGER.error( this.getToken(), new Throwable( e ) );
                }
            }
        }
    }[/code]

Abaixo segue a thread que processa o canal e retira do buffer o customer:

[code]
public void run(){


try {
this.getBuffer().remove( this.getCustomer() );
} catch(Exception e) {
LOGGER.error( this.getToken(), new Throwable( e ) );
}
}[/code]

Uma outra parte do código que pode estar dando problema, que eu acho é essa:

private String resultServer = null; private BufferedReader fromServer; private Socket socket; private void setResultServer() throws IOException{ if(this.socket != null && this.socket.isConnected() && this.isLoggerResponse() ){ double startTime = System.currentTimeMillis(); for(String temp = null; (temp = this.fromServer.readLine()) != null;){ this.resultServer += temp; } } else { this.resultServer = null; } }
Eu sempre tenho que pegar o retorno do servidor. Não vejo outra maneira de fazer isso. Alguém teria alguma ideia de como melhorar este método?

É difícil responder sua pergunta, pq não conheço nem o que sua aplicação faz, nem o seu protocolo, e nem o comportamento do seu servidor.

Geralmente, num modelo síncrono de envio/espera pela resposta o que você tem são:

a) Uma thread isolada, que apenas dê dados vindo da rede, e os empacota num pacote mínimo e codificado. Essa classe encaminha os dados para uma thread decodificadora;
b) Uma thread, que faz a decodificação da mensagem. Essa thread usa algum campo de destino, para saber para onde responder a requisição.
c) Uma série de threads clientes. Ao enviar um pacote, a thread cliente cria um objeto local (através de um ThreadLocal) que irá tratar a requisição. Nesse objeto, bloqueia-se a thread cliente. A thread decodificadora contém um mapa desses objetos, e irá notifica-los assim que mensagem chegar, liberando assim a thread cliente para utilizar a informação vinda da rede.

No caso, eu não baseio meus protolocos em \n, justamente para não depender do método readLine. Tipicamente, o que faço é colocar nos primeiros 4 bytes o tamanho da mensagem, e nos 4 seguintes o tipo. Em seguida, a mensagem em si. Essa organização é útil pq a classe que lê da rede só precisa se incomodar com esses 4 primeiros bytes, enquanto a classe decodificadora com os 4 seguintes. O processo então pode ser dividido em camadas, cada uma desempacotando parte do pacote de dados. Esse modelo é explicado aqui:
http://www.guj.com.br/posts/list/136538.java#735860

Caso criptografia seja necessária, vc pode incluir uma camada entre essas duas.