スレッド基本
スレッド状態図
下記の記述は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が発生する可能性もある