Java同時/マルチスレッド

10446 ワード

Javaマルチスレッド
スレッドを実装する2つの方法:
a.Threadクラスを継承し、start()を起動します.
b.Runnableインタフェースを実現し、run方法を実現する.
 
1.基本スレッド
package com.sam.thread; public class SimpleThread extends Thread {     private int countDown = 5;     private static int threadCount = 0;     public SimpleThread() {         super(""+++threadCount);//store the thread name         start();     }     public String toString() {         return "#"+ getName() + ": "+ countDown;     }     public void run() {         while (true) {             System.out.println(this);             if (--countDown == 0)                 return;         }     }     public static void main(String[] args) {         for (int i = 0; i < 5; i++) {             new SimpleThread();         }     } }
package com.sam.thread;

public class SimpleThread extends Thread {
	private int countDown = 5;
	private static int threadCount = 0;

	public SimpleThread() {
		super(" " + ++threadCount); // store the thread name
		start();
	}

	public String toString() {
		return "#" + getName() + ": " + countDown;
	}

	public void run() {
		while (true) {
			System.out.println(this);
			if (--countDown == 0)
				return;
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new SimpleThread();
		}
	}
}

結果:
# 1: 5
# 1: 4
# 1: 3
# 1: 2
# 1: 1
# 3: 5
# 3: 4
# 3: 3
# 3: 2
# 3: 1
# 2: 5
# 5: 5
# 5: 4
# 5: 3
# 5: 2
# 5: 1
# 2: 4
# 2: 3
# 2: 2
# 2: 1
# 4: 5
# 4: 4
# 4: 3
# 4: 2
# 4: 1
 
 
 
2.yield()は、譲歩して、他のスレッドにCPUを使用させ、結果をより均衡させることができます.
package com.sam.thread;

public class YieldThread extends Thread {
	private int countDown = 5;
	private static int threadCount = 0;

	public YieldThread() {
		super(" " + ++threadCount); // store the thread name
		start();
	}

	public String toString() {
		return "#" + getName() + ": " + countDown;
	}

	public void run() {
		while (true) {
			System.out.println(this);
			if (--countDown == 0)
				return;
			yield();
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new YieldThread();
		}
	}
}

結果:
# 1: 5
# 2: 5
# 3: 5
# 1: 4
# 2: 4
# 5: 5
# 3: 4
# 1: 3
# 5: 4
# 3: 3
# 1: 2
# 5: 3
# 3: 2
# 1: 1
# 5: 2
# 4: 5
# 3: 1
# 5: 1
# 2: 3
# 4: 4
# 2: 2
# 2: 1
# 4: 3
# 4: 2
# 4: 1

 
3.sleep、しばらく休眠してから実行する
package com.sam.thread;

public class SleepThread extends Thread {
	private int countDown = 5;
	private static int threadCount = 0;

	public SleepThread() {
		super(" " + ++threadCount); // store the thread name
		start();
	}

	public String toString() {
		return "#" + getName() + ": " + countDown;
	}

	public void run() {
		while (true) {
			System.out.println(this);
			if (--countDown == 0)
				return;
			try {
				sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new SleepThread();
		}
	}
}

結果:
# 1: 5
# 3: 5
# 2: 5
# 5: 5
# 4: 5
# 1: 4
# 2: 4
# 4: 4
# 3: 4
# 5: 4
# 1: 3
# 2: 3
# 3: 3
# 4: 3
# 5: 3
# 2: 2
# 4: 2
# 3: 2
# 1: 2
# 5: 2
# 1: 1
# 2: 1
# 4: 1
# 3: 1
# 5: 1

 
4.優先度setPriority()
package com.sam.thread;

public class PriorityThread extends Thread {
	private int countDown = 5;
	private static int threadCount = 0;

	public PriorityThread(int priority) {
		super(" " + ++threadCount); // store the thread name
		setPriority(priority);
		start();
	}

	public String toString() {
		return "#" + getName() + ": " + countDown;
	}

	public void run() {
		while (true) {
			System.out.println(this);
			if (--countDown == 0)
				return;			
		}
	}

	public static void main(String[] args) {
		new PriorityThread(Thread.MAX_PRIORITY);
		for (int i = 0; i < 5; i++) {
			new PriorityThread(Thread.MIN_PRIORITY);
		}
	}
}

結果:優先度の高い先行実行
# 1: 5
# 1: 4
# 1: 3
# 1: 2
# 1: 1
# 3: 5
# 3: 4
# 3: 3
# 3: 2
# 3: 1
# 5: 5
# 5: 4
# 5: 3
# 5: 2
# 5: 1
# 2: 5
# 2: 4
# 2: 3
# 2: 2
# 2: 1
# 4: 5
# 4: 4
# 4: 3
# 6: 5
# 6: 4
# 6: 3
# 6: 2
# 6: 1
# 4: 2
# 4: 1

 
5.バックグラウンドスレッド(daemon)
バックグラウンド以外のすべてのスレッドが終了すると、スレッドは終了します.例えば、ある時点でスレッドがsleepになり、プログラムが終了します.
package com.sam.thread;

public class DaemonThread extends Thread {
	private int countDown = 5;
	private static int threadCount = 0;

	public DaemonThread() {
		super(" " + ++threadCount); // store the thread name
		setDaemon(true);
		start();
	}

	public String toString() {
		return "#" + getName() + ": " + countDown;
	}

	public void run() {
		while (true) {
			System.out.println(this);
			if (--countDown == 0)
				return;
			try {
				sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new DaemonThread();
		}
	}
}

結果:
# 1: 5
# 3: 5
# 5: 5
# 4: 5
# 2: 5

 
6.join()とinterrupt()
package com.sam.thread;

class A extends Thread {
	public A() {
		start();
	}
	public void run() {
		try {
			System.out.println("A started.");
			sleep(1000);
		} catch (InterruptedException e) {
			System.out.println("Sleep interrupted");
		}
	}
}

public class JoinThread extends Thread {
	A a;
	public JoinThread(A a) {
		this.a = a;
		start();
	}
	public void run() {
	
		try {
			a.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("JoinThread started.");
	}
	public static void main(String[] args) {
		A a = new A();
		JoinThread jt = new JoinThread(a);
		a.interrupt();
	}
}

結果:
A started.
Sleep interrupted
JoinThread started.

 
7.Runnableインタフェース
package com.sam.thread;

public class RunnableThread implements Runnable {

	private int countDown = 5;

	public String toString() {
		return "#" + Thread.currentThread().getName() + ": " + countDown;
	}

	@Override
	public void run() {
		while (true) {
			System.out.println(this);
			if (--countDown == 0)
				return;
		}
	}

	public static void main(String[] args) {
		for (int i = 1; i <= 5; i++) {
			new Thread(new RunnableThread(), "" + i).start();
		}
	}
}

runnableインタフェース自体はスレッドの特性を持たず、実行するか、個別のThreadオブジェクトを作成します.
 
8.リソースへの不正アクセス
package com.sam.thread;

public class AlwaysEven {
	int i;

	void next() {
		i++;
		i++;
	}

	int get() {
		return i;
	}

	public static void main(String[] args) {
		final AlwaysEven ae = new AlwaysEven();
		new Thread() {
			public void run() {
				while (true) {
					int j = ae.get();
					if (j % 2 != 0) {
						System.out.println(j);
						System.exit(0);
					}
				}
			}
		}.start();
		while (true) {
			ae.next();
		}
	}
}

結果:
1501

 
9.共有リソース競合の解決
共有リソースにアクセスする各メソッドにsynchronizedを追加する必要があります.そうしないと、追加しないメソッドはロックを無視します.
package com.sam.thread;

public class AlwaysEven {
	int i;

	synchronized void next() {
		i++;
		i++;
	}

	synchronized int get() {
		return i;
	}

	public static void main(String[] args) {
		final AlwaysEven ae = new AlwaysEven();
		new Thread() {
			public void run() {
				while (true) {
					int j = ae.get();
					if (j % 2 != 0) {
						System.out.println(j);
						System.exit(0);
					}
				}
			}
		}.start();
		while (true) {
			ae.next();
		}
	}
}

 
10. volatile
コンパイラの最適化は禁止され、スレッドはオブジェクトのプライベートコピーを保持できず、効率に影響します.
 
11.臨界領域
複数のスレッドアクセスメソッドの一部のコードを防止します.
synchronized(syncObject) {
    // This code can only be access
    // by one thread at a time
}

 
12.スレッドの状態
新規(new)
準備完了(Runnable)
死亡(Dead)
ブロッキング(Blocked)
 
13. notify()
wait()のスレッドを起動します.
 
zz