第六章読書ノート


ほとんどのコンカレントアプリケーションは、タスクの実行をめぐって管理されています.タスクとは抽象的で離散的な作業ユニットである.
タスクの実行をめぐってアプリケーションを管理する上で最も重要なのは、明確なタスク境界を示すことです.
ほとんどのサーバ・アプリケーションでは、個別の顧客リクエストという自然なタスク境界が選択されています.Webサーバ、メールサーバ、ファイルサーバ、EJBコンテナ、データベースサーバ.これらのサーバは、リモート・クライアントがネットワーク接続を介して送信する要求を受け入れます.
 
アプリケーションサーバ内部のスケジューリングポリシー:
1)手順の実行
  class SingleThreadWebServer{
  public static void main(String[] args) throws IOException{
  ServerSocket socket = new ServerSocket(80);
    while(true){
        Socket connetion = socket.accept();
        handleRequest(connection);
     }
  }
}
2)タスクのスレッドを明示的に作成する
class ThreadPerTaskWebServer {
    public static void main(String[] args) throws IOException {
        ServerSocket socket = new ServerSocket(80);
        while (true) {
            final  Socket connection = socket.accept();
            Runnable task = new Runnable() {
                    public void run() {
                        handleRequest(connection);
                    }
                };
            new Thread(task).start();
        }
    }
}

スレッドの作成に制限がないという欠点:
1)スレッドの作成破棄自体のオーバーヘッド
2)アクティブスレッドはシステムリソース、特にメモリを消費する
3)安定性
 
Executorフレームワーク
executorは単純なインタフェースにすぎませんが、柔軟で強力なフレームワークに基づいています.このフレームワークは非同期実行に使用できます.
多くの異なるタイプのタスク実行ポリシーをサポートします.また,タスクコミットとタスク実行との間のデカップリングに標準的な方法を提供し,Runnableを用いてタスクを記述するために汎用的な方法を提供した.Executorの実装では、ライフサイクルのサポートやフック関数も提供され、統計収集、アプリケーション管理などの追加が可能です.
メカニズムやモニタなどの拡張.
Executorは生産者-消費者モデルに基づいている.
 
ExecutorによるWebサーバ
 
class TaskExecutionWebServer {
    private static final int NTHREADS = 100;
    private static final Executor exec
        = Executors.newFixedThreadPool(NTHREADS);

    public static void main(String[] args) throws IOException {
        ServerSocket socket = new ServerSocket(80);
        while (true) {
            final Socket connection = socket.accept();
            Runnable task = new Runnable() {
                public void run() {
                    handleRequest(connection);
                }
            };
            exec.execute(task);
        }
    }
}

Executorは、タスクの要求と実行をデカップリングし、異なるExecutor実装を置き換えるだけでサーバの動作を変更できます.
 
public class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) {
        new Thread(r).start();
    };
}
public class WithinThreadExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    };
}

 
 
Executorsでは、スレッドプールを作成するための静的メソッドがいくつか用意されています.
新SingleThreadExecutor:タスクを実行するスレッドが1つしかないExecutorServiceオブジェクトを生成します.タスクが1つ以上ある場合、タスクはタスクキューに規定された順序(FIFO、LIFO、優先度)で実行されます.現場が異常に閉鎖された場合、新しい補充があります.
新CachedThreadPool():スレッドプールを持つExecutorServiceオブジェクトを生成します.スレッドプールのサイズは必要に応じて調整され、スレッドがタスクを実行した後、スレッドプールに戻り、次のタスクを実行するために使用されます.
新FixedThreadPool(int poolSize):poolSizeというサイズのスレッドプールを持つExecutorServiceオブジェクトを生成します.poolSizeより大きいタスクの場合、タスクはqueueに配置されて順次実行されます.
NewSingleThreadScheduledExecutor:スレッドプールのサイズが1であるScheduledExecutorServiceオブジェクトを生成します.タスクが1つ以上ある場合、タスクは前後順に実行されます.
NewScheduledThreadPool(int poolSize):スレッドプールのサイズがpoolSizeであるScheduledExecutorServiceオブジェクトを生成します.タスクの数がpoolSizeより大きい場合、タスクは1つのqueueで実行を待機します.
Excetorのライフサイクル
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;

public class LifecycleWebServer
{
    private final ExecutorService exec = Executors.newSingleThreadExecutor();

    public void start()
    {

        // while (true)// 
        while (!exec.isShutdown())
        {
            try
            {
                final String requestId = Client.request();
                exec.execute(new Runnable()
                {
                    public void run()
                    {
                        handleRequest(requestId);
                    }
                });
                Thread.sleep(1000);
            }
            catch (RejectedExecutionException e)
            {
                if (!exec.isShutdown())
                {
                    System.out.println("task submission rejected" + e.toString());
                }
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void stop()
    {
        exec.shutdown();
    }

    public void handleRequest(String requestId)
    {
        if (requestId.equals("stop"))
        {
            stop();
        }
        else
        {
            System.out.println(" " + requestId);
        }
    }

}

 
public class Client
{
    public static void main(String[] args)
    {
        Runnable run = new Runnable()
        {
            public void run()
            {
                while (true)
                {
                    putRequest();
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch (InterruptedException e)
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        };
        new Thread(run).start();

        LifecycleWebServer server = new LifecycleWebServer();
        server.start();

    }

    public static String request = "stopstopstop";

    public static String request()
    {
        return request;
    }

    public static void putRequest()
    {
        request = request.substring(0, request.length() - 1);
        System.out.println(" " + request);
    }
}