スレッド基本

スレッド状態図

下記の記述はJava系

★遅延処理

目的:性能を高める

場面:時間がかかるインスタンス化

効率悪い

public class TestClass {

private final FieldType field;

synchronized FieldType getField() {

if(field == null) {

field = createField();

}

return field;

}

}

効率良い

1.staticの場合

public class TestClass {

private static class FieldHolder {

static final FieldType field = createField();

}

static FieldType getField() {

return FieldHolder.field;

}

}

2.instanceの場合(Singleton)

public class TestClass {

private volatile FieldType field;

FieldType getField() {

FieldType result = field; //毎回メインメモリから読むよりローカルで

if(result == null) {

synchronized (this) {

result = field;

if(result == null) {

field = result = createField();

}

}

}

return result;

}

}

3.instanceの場合(重複可)

public class TestClass {

private volatile FieldType field;

FieldType getField() {

FieldType result = field;

if(result == null) {

field = result = createField();

}

return result;

}

}

★マルチスレッド中のstatic変数

static final int MAX_VALUE = 100;

static final String DEL_FLG = "DEL_FLG";

static final BigDecimal MAX_VALUE = new BigDecimal("0.01");

static final Pattern PATTERN = Pattern.compile("^[0-9a-zA-Z]*$");

static final DateFormat DATE_FORMAT

= new SimpleDateFormat("yyyy-MM-dd"); × スレッドセーフではない

static final Map<String, String> GENDER_MAP; × 要素が変更できる

static{

GENDER_MAP = new HashMap<String, String>();

GENDER_MAP.put("1", "男");

GENDER_MAP.put("2", "女");

}

static final Map<String, String> GENDER_MAP;

static{

HashMap<String, String> map = new HashMap<String, String>();

map.put("1", "男");

map.put("2", "女");

GENDER_MAP = Collectins.unmodifiableMap(map);

}

★スレッド作成の基本

・Threadクラス(実はThreadクラスもRunnableインターフェースの実装)

public class Sample extends Thread{

private long sleepTime;

public Sample(String name, long sleepTime) {

super(name);

this.sleepTime = sleepTime;

}

@Override

public void run() {

// do something

}

}

// 利用側

Sample thread1 = new Sample("thread1", 200);

Sample thread2 = new Sample("thread2", 300);

thread1.start();

thread2.start();

・Runnableインターフェース

public class Sample implements Runnable{

private String name;

private long sleepTime;

public Sample(String name, long sleepTime) {

this.name = name;

this.sleepTime = sleepTime;

}

@Override

public void run() {

// do something

}

}

// 利用側

Sample sample1 = new Sample("thread1", 200);

Sample sample2 = new Sample("thread2", 300);

Thread thread1 = new Thread(sample1);

Thread thread2 = new Thread(sample2);

thread1.start();

thread2.start();

java.lang.Threadクラスのメソッド

String getName()

void setName(String name)

void interrupt()

boolean isAlive()

void join()

void run()

static void sleep(long millis)

void start()

static void yield()

★Thread name設定(Debug用)

Thread thread = new Thread("name") {

public void run() {...}

};

あるいは

Thread thread = new Thread() {

public void run() {...}

};

thread.setName("name");

public class MyThread extends Thread {

public MyThread() {

super("name");

}

public void run() {...}

}

MyThread thread = new MyThread ();

Thread thread = new Thread(task);

thread.setName("name");

あるいは

Thread thread = new Thread(task, "name");

★割り込み

Thread thread = new Thread("interrupt") {

public void run() {

for (;;) {

...

if (Thread.interrupted()) {

break;

}

あるいは

try {

foo();

} catch (InterruptedException e) {

break;

} catch (Exception e) {

...

}

}

}

public void foo() throws InterruptedException {

if (Thread.interrupted()) {

throw new InterruptedException();

}

}

};

★sleep vs wait

sleep

スレッドのコントロール

Threadクラスのメソッド

ロック処理を解放しない

どこでも書ける

wait

スレッド間の通信。notifyとnotifyAllも併用。

Objectクラスのメソッド

ロック処理を解放する

ロックブロック内に書く

両方ともにInterruptedExceptionをcatchする必要がある

synchronizedメソッド/ブロック以外でwait()、notify()、notifyAll()メソッドを呼び出さない

※オブジェクトをロックした状態が必要

★スレッドを停止する方法

※Java APIのstopメソッドとinterruptメソッドは使えない

方法1

class StopThread extends Thread{

private volatile boolean stop = false;

@Override

public void run() {

while(stop){

// do something

}

}

public void shutdown(){

stop = true;

}

}

方法2

class StopThread extends Thread{

private final AtomicBoolean stop = new AtomicBoolean(false);

@Override

public void run() {

while(stop.get()){

// do something

}

}

public void shutdown(){

stop.set(true);

}

}

方法3

class StopThread extends Thread{

private boolean stop = false;

@Override

public void run() {

while(isStop()){

// do something

}

}

public synchronized boolean isStop(){

return stop;

}

public synchronized void shutdown(){

stop = true;

}

}

★スレッドの優先順位

public void start(int priority){

Thread t = new Thread(this);

t.setPriority();

t.start();

}

※priorityは下記の定数を使うべき

・Thread.MAX_PRIORITY

・Thread.MIN_PRIORITY

・Thread.NORM_PRIORITY

★スレッドの例外処理

class Server implements Runnable{

public Server() {

Thread t = new Thread(this);

t.setUncaughtExceptionHandler(new ServerExceptionHandler());

t.start();

}

@Override

public void run() {

// do something

throw new RuntimeException();

}

private static class ServerExceptionHandler implements

Thread.UncaughtExceptionHandler{

@Override

public void uncaughtException(Thread t, Throwable e) {

System.out.println(t.getName());

e.printStackTrace();

new Server(); // 再起動

}

}

}

※注意点

・リソースがロックされる場合、再起動しても解決できないため、すべてのスレッドを停止しよう

・例外が発生した場合、再起動したら、一部ユーザに対し、業務ロジックが破壊される可能性がは高い

・OutOfMemoryが発生する可能性もある