Javaにおける例外処理とマルチスレッドプログラミング

例外処理の基本

finallyブロックの重要性:tryブロック内で例外が発生するかどうか、あるいはcatchブロックで例外が捕捉されるかどうかに関わらず、finallyブロック内のコードは常に実行されます。

マルチスレッドの実装方法

Threadクラスを継承する方法

public class ThreadDemo extends Thread {
    public static void main(String[] args) {
        ThreadDemo worker = new ThreadDemo("ワーカースレッド");
        worker.start();
        
        Thread.currentThread().setName("メインスレッド");
        for (int count = 0; count < 10; count++) {
            try {
                Thread.sleep(1000);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + count);
        }
    }
    
    public ThreadDemo() {}
    
    public ThreadDemo(String threadName) {
        super(threadName);
    }
    
    @Override
    public void run() {
        for (int count = 0; count < 10; count++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            System.out.println(getName() + ":" + count);
        }
    }
}

Runnableインターフェースを実装する方法

public class TaskExecutor implements Runnable {
    public static void main(String[] args) {
        Runnable task = new TaskExecutor();
        Thread workerThread = new Thread(task);
        workerThread.start();
        
        for (int count = 0; count < 10; count++) {
            System.out.println("メインスレッド:" + count);
        }
    }
    
    @Override
    public void run() {
        for (int count = 0; count < 10; count++) {
            System.out.println("サブスレッド:" + count);
        }
    }
}

注意:継承は単一継承しかできないため、インターフェース実装方式が推奨されます。

匿名内部クラスを使用する方法

public class AnonymousThreadDemo {
    public static void main(String[] args) {
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }.start();
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }).start();
    }
}

スレッドセーフティの実現

同期ブロックの使用

public class SharedResource implements Runnable {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();
        
        new Thread(resource).start();
        new Thread(resource).start();
        new Thread(resource).start();
    }
    
    private int counter = 10;
    private final Object lock = new Object();
    
    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                if (counter > 0) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + counter);
                    counter--;
                }
            }
        }
    }
}

同期メソッドの使用

public class SynchronizedMethod implements Runnable {
    public static void main(String[] args) {
        SynchronizedMethod instance = new SynchronizedMethod();
        
        new Thread(instance).start();
        new Thread(instance).start();
        new Thread(instance).start();
    }
    
    private int counter = 10;
    
    @Override
    public void run() {
        while (true) {
            processResource();
        }
    }
    
    public synchronized void processResource() {
        if (counter > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + counter);
            counter--;
        }
    }
}

静的同期メソッドの使用

public class StaticSyncMethod implements Runnable {
    public static void main(String[] args) {
        StaticSyncMethod instance = new StaticSyncMethod();
        
        new Thread(instance).start();
        new Thread(instance).start();
        new Thread(instance).start();
    }
    
    private static int counter = 10;
    
    @Override
    public void run() {
        while (true) {
            processStaticResource();
        }
    }
    
    public static synchronized void processStaticResource() {
        if (counter > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + counter);
            counter--;
        }
    }
}

スレッド状態とプロデューサー/コンシューマーパターン

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        Object monitor = new Object();
        
        // プロデューサースレッド
        new Thread() {
            @Override
            public void run() {
                synchronized (monitor) {
                    try {
                        monitor.wait();
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    System.out.println("プロデューサー:製品生産開始");
                    for (int time = 0; time < 3; time++) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                        System.out.println((time + 1) + "秒経過");
                    }
                    System.out.println("プロデューサー:製品生産完了");
                    monitor.notify();
                }
            }
        }.start();
        
        // コンシューマースレッド
        new Thread() {
            @Override
            public void run() {
                synchronized (monitor) {
                    System.out.println("コンシューマー:製品を要求、生産待機中");
                    monitor.notify();
                    try {
                        monitor.wait();
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    System.out.println("コンシューマー:製品使用開始");
                }
            }
        }.start();
    }
}

スレッドプールの活用

public class ThreadPoolExample implements Runnable {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        threadPool.submit(new ThreadPoolExample());
        threadPool.submit(new ThreadPoolExample());
        threadPool.submit(new ThreadPoolExample());
        
        threadPool.shutdown();
    }
    
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "がタスクを実行中");
    }
}

タグ: Java例外処理 マルチスレッド 同期処理 スレッドセーフティ スレッドプール

8月18日 02:25 投稿