スレッドの基本概念
現代のオペレーティングシステムはマルチタスクをサポートしています。この中でスレッドはマルチタスクを実現するための重要な手段です。
プロセスとはメモリ内で実行されるアプリケーションのことで、それぞれ独立したメモリ領域を持ちます。1つのプロセス内に複数のスレッドが存在可能です。Windowsシステムではexeファイルの実行がプロセスとして扱われます。
Javaスレッドの基本
Javaではスレッドに関連する2つの重要な概念があります:
- java.lang.Threadクラスのインスタンス
- スレッドの実行
スレッドの作成方法
主に2つの方法があります:
- Threadクラスを継承する方法
- Runnableインターフェースを実装する方法
Runnableインターフェースの実装例
public class Task implements Runnable {
private String taskName;
public Task(String name) {
this.taskName = name;
}
@Override
public void run() {
for(int i=0; i<5; i++) {
// タイムコンsumingな処理を模擬
for(long j=0; j<100000000; j++);
System.out.println(taskName + ": " + i);
}
}
public static void main(String[] args) {
Task task1 = new Task("タスクA");
Task task2 = new Task("タスクB");
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
}
}
スレッドの状態遷移
スレッドには以下の主要な状態があります:
- 新規状態(New)
- 実行可能状態(Runnable)
- 実行状態(Running)
- 待機状態(Waiting)
- 終了状態(Dead)
スレッドの同期とロック
複数のスレッドが共有データにアクセスする際、データ競合を防ぐために同期が必要です。主に以下のような方法があります:
- synchronizedメソッド
- synchronizedブロック
デッドロックの例
public class DeadlockExample {
private static class Resource {}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public void method1() {
synchronized(resourceA) {
synchronized(resourceB) {
// 処理
}
}
}
public void method2() {
synchronized(resourceB) {
synchronized(resourceA) {
// 処理
}
}
}
}
スレッドプール
Java 5から導入されたスレッドプール機能を使用することで、効率的なスレッド管理が可能になります。主な種類:
- 固定サイズスレッドプール
- キャッシュ可能スレッドプール
- スケジューリング可能なスレッドプール
固定サイズスレッドプールの例
ExecutorService pool = Executors.newFixedThreadPool(2);
Thread task1 = new MyThread("タスク1");
Thread task2 = new MyThread("タスク2");
pool.execute(task1);
pool.execute(task2);
pool.shutdown();
高レベルスレッド制御
条件変数
class SharedResource {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean flag = false;
public void waitForSignal() {
lock.lock();
try {
while(!flag) {
condition.await();
}
// 処理
} finally {
lock.unlock();
}
}
public void sendSignal() {
lock.lock();
try {
flag = true;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
アトミック変数
java.util.concurrent.atomicパッケージはアトミック操作を提供します:
public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
}
サイクリックバリア
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("すべてのサブタスク完了");
});
new Thread(() -> {
// タスク処理
barrier.await();
}).start();