Socket、Threadの使用記録


詳細
多すぎる时间のWebプロジェクトをして、Socketのこのような基础のまた重要なインタフェースはすべてすぐ忘れて、たまにしますが、しかしすべてあまり深くなくて、ちょうど前の时间はまたSocket类の応用をして、またSocketインタフェースに対していくつか新しい认识があって、先に覚えておきます
 
ブログに載せるとすぐにミスを指摘されたので、感謝しています. 
 
1.SocketStreamトランケート文字
FileStreamの最後のカットオフ文字は-1で、ファイルを操作するときに次のような判断ができます.
BufferedReader buffer = new BufferedReader(new InputStreamReader(socket
		 .getInputStream(), "UTF-8"));
DataInputStream in = new DataInputStream(connection.getInputStream());
while ((count = in.read(buffer)) > 0) {
        out.write(buffer, 0, count);
}

この技はSocketの中では効かない.もしこの判断が成立するには、相手のSocketが自発的に閉じる必要があるからだ.クライアントがEOFを受け取ってからこの判断を成立させることができる.そうしないと、相手は関係なく、countは永遠に-1を得られず、そこに詰まってしまう. 
Socketインタフェースが互いに転送できるものは双方が合意したものであり、どんな文字も現れる可能性があるため、-1だけで遮断判断をするのは間違っている.もし双方が-1または特定の特殊文字を遮断標識としてもよいと認定すれば、転送ファイルが-1にならないことを知っている場合に限って、このような判断の習慣はC言語から来ている可能性がある.しかしC言語にはEOFがあり、Javaでは提供されていません.
この問題を解決する方法は、友人の指摘を経てこうなった.
int BS=100,count=0;
byte[]buffer=new byte[BS];
int has_readed=0;
DataInputStream in = new DataInputStream(connection.getInputStream());  
while ((count = in.read(buffer)) > 0 && has_readed < BS) {  
     int left=BS-has_readed;
     out.write(buffer, 0, count>left?left:count);  
     has_readed+=count;
    }

 上のコードは複雑になりました.
A.読み出すたびに指定された長さのbyteストリームを読むので、プロトコルに長さを書き、指定された内容を読み取ることができ、読み取りが正確で、ブロックする必要がなく、効率も高い.
B.hasを1つ採用するreadedはカウンタとして,ネットワークブロックの場合にデータが読めないことを防止し,プログラムの堅牢性を向上させる.
 
2.count = in.read(buffer)
これは普通に見えますが、以前はよく考えていませんし、分析する資料もありませんでした.ここでよく見てみましょう.C言語では1つの方法で2つのパラメータを返すことができますが、Javaでは違法です.そして、このin.read(byte b[])という方法も似たようなことをしました.
A.readメソッドで読み取ったbufferの個数で、値が読み取れない場合は-1を返します.
B.readメソッドは、読んだものをbufferというbyte配列に添付することで、2つのパラメータを返す効果があります.配列はObjectオブジェクトなので、パラメータとして伝達すれば付与できますが、基本的なタイプではできません.オブジェクトだけができます(リスト、Mapなど).
 
3.byteかStringか
最初にJavaに接触した时にSocketをして、Stringのタイプで伝送して、とても便利で、双方のインタフェースの処理はすべて简単で更に直観的で、今回のインタフェースの伝送はbyte[]で、やった私はとても気がふさいで、私のJavaの基础がしっかりしていないかもしれません(后で同僚のコメントはあなたがCをあまり书いたことがないに违いありません......)、byte[]は気分が悪くなって、わけのわからない数字が山積みになっているのに、いろいろなタイプに変換して数位をコントロールしたりして、うっかりミスをしてしまいます.最初はお客様の技術的なスタイルの習慣があると思っていましたが、後で考えてみると、このSocketは言語間のコミュニケーションの架け橋であり、Javaだけのために作ったのではなく、C言語のようにStringを用意していないタイプですね.実はStringタイプはまだしも、どう言えば実現できるのか、Socketでシーケンス化されたオブジェクトを渡すのはもっと面倒だという人もいます.byte[]配列でタイプ変換なども熟知できます.
 
4.Threadの代わりにExcutorを使用します(内容はJava Concurrency in Practiceから来ています.詳細を見つける必要がある場合は、原書第6章を参照してください).
クラシックな面接問題:Javaはどのような方法でスレッドを実現しますか?答え:ThreadとRunnableインタフェースを継承しますが、1.5以降はそうは答えられません.java.util.concurrentを加えて、「Java同時プログラミング実践」の一言を使うべきです.
               :

    new Thread(runnable).start()

                           ,       Executor  Thread

 Socketを使うときはよくこう書きます.
ServerSocket socket = new ServerSocket(7001);
While(true){
     final Socket connection = socket.accept();
    Runnable task = new Runnable(){
              public void run(){
                      //hanld reuqust code
              }
    };
    new Thread(task).start();
}
 これは問題ないように見えますが、すべての教科書にはこのように書かれています.1つのスレッドを要求し、制限なくスレッドを作成し、プロトタイプや製品開発時によく表現されています.しかし、このようなタスクごとにスレッド(thread-per-task)メソッドには実際の欠陥があり、特に大量のスレッドを作成する必要がある場合はさらに際立っています.
A.スレッドライフサイクルのオーバーヘッド
B.資源消費量
C.安定性
具体的な説明は原書を参照することができて、現れた問題は理解しやすいので、たとえあなたのプログラムが1.4バージョンを使っていても(Third party)スレッドに大きく依存し、特に大量同時処理が必要な場合はjava.util.concurrentが提供するスレッドプールを採用するべきであり、concurrentはThreadより安定して機能が豊富であり、マルチスレッド同時プログラムをより安定した表現にすることができる.
私たちの元のインタフェースプログラムは元のThreadを採用して、同時量の要求は500個に達して、私を異常に頭が痛いならば、Concurrentスレッドプールを採用すればもっと良い同時性能を得ることができて、サーバーの安定性を確保することができます(残念ながらしばらく実践する機会がありません). 
 
5.期待JDK 7
JDK 7は現在開発段階にあり、現在の傾向はSUNがJDK 7にマルチコア開発に対してより良いサポートを提供することである.
先日、JavaEyeニュースでJDK 7の多核開発への支援に関する質問を書いた人を見て、考えてみる価値もあります.
一つ目はjavaがサポートスレッド開発パッケージを提供するだけではなく、Scala、Erlangのように言語レベルでマルチコアをサポートしているはずだ.
2つ目は、マルチコア時代に直面して、8コア、16コアをどのように利用するかというプロセッサは、CPUの性能をどのようによりよく発揮するかだけでなく、マルチコアの潜在力を発揮することができても、多くのI/O操作の処理に直面しなければならないため、I/O処理はより難しいボトルネックになります.このようなI/Oリソースはロックポリシーしか使用できないからです.
これらのものはまだ遠いようですが、面白いです.Javaが参加したい文法糖や、動的言語のサポートに対する多くの論争もあります.JDK 7がどうなるか分かりません.つまり、Javaはますます複雑になり、ソフトウェア界の注目を集めています.