JAVA同時プログラミング1_マルチスレッドの実装
JAVAでスレッドを作成する2つの方法:Threadを継承するかRunnableインタフェースを実装します.
1 Threadクラスを継承しrunメソッドを書き換える:
2 Runnableインタフェースを実装し,runメソッドを書き換え,パラメータとしてThreadオブジェクトに渡す.
2つの方法の違いは何ですか?ソースコードを見ると、ThreadクラスはRunnableインタフェースを実装していることがわかります.
Threadクラスのstart()メソッドを呼び出すと、ローカルメソッドstart 0()が呼び出されます.
要するにrunメソッドに呼び出されます.
Runnableを使用してThreadを構築すると、Runnableオブジェクトのrunメソッドが呼び出されます.さもないと、何もしません.しかし,継承方式でスレッドを実現すると,Threadクラスのrunメソッドは多態でまったく実行されないため,書き換えrunメソッドが実行される.
たとえば,Threadから引き継いでrunメソッドを実装し,RunnableによってThread結果を構築するとどのrunメソッドが実行されるのか.答えは確定です.Threadクラスから継承されたrunメソッドが実行されます.
いったいThreadを使うのか、それともRunnableを使うのか.
Runnableインタフェースを実装することは、Threadクラスを継承することよりも優れています.
1.同一のプログラムコードが複数あるスレッドに適合して同一のリソースを処理し、Threadを継承する必要がある共有リソースをstaticに設定する.
2.javaでの単一継承の制限を回避
3.プログラムの堅牢性を高め、コードは複数のスレッドで共有でき、コードとデータは独立している.
最初のコードのcountフィールドをstaticに変更
staticを使用してもリソースを共有しても、Threadを作成したRunnableオブジェクトが同じであることを前提として、2番目の方法でマルチスレッドを実装してもよいことがわかります.
注意深く見ると、印刷の構造は私たちが予想していたものではありません.例えば、
//Thread[thread_1,5,main]--->2
//Thread[thread_2,5,main]--->2
このような結果が出たのは,マルチスレッド同時の制御不能性のためであり,スレッド同期については後述する.
1 Threadクラスを継承しrunメソッドを書き換える:
/**
* : Thread
*
* @author qhyuan1992
*
*/
class MyThread extends Thread{
private int count;// static
public MyThread(String id){
super(id);
}
public void run() {
while (count < 5) {
count ++;
System.out.println(currentThread() + "--->" + count);
}
}
}
class Test{
public static void main(String[] args) {
Thread t1 = new MyThread("thread_1");
Thread t2 = new MyThread("thread_2");
t1.start();
t2.start();
}
}
// output( )
//Thread[thread_1,5,main]--->1
//Thread[thread_2,5,main]--->1
//Thread[thread_1,5,main]--->2
//Thread[thread_1,5,main]--->3
//Thread[thread_1,5,main]--->4
//Thread[thread_2,5,main]--->2
//Thread[thread_1,5,main]--->5
//Thread[thread_2,5,main]--->3
//Thread[thread_2,5,main]--->4
//Thread[thread_2,5,main]--->5
2 Runnableインタフェースを実装し,runメソッドを書き換え,パラメータとしてThreadオブジェクトに渡す.
/**
* : Runnable
*
* @author qhyuan1992
*/
class MyRunnable implements Runnable{
private int count;
public void run() {
while (count < 5) {
count ++;
System.out.println(Thread.currentThread() + "--->" + count);
}
}
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
}
}
// output( Runnable Thread )
//Thread[Thread-0,5,main]--->2
//Thread[Thread-1,5,main]--->2
//Thread[Thread-1,5,main]--->3
//Thread[Thread-1,5,main]--->4
//Thread[Thread-1,5,main]--->5
2つの方法の違いは何ですか?ソースコードを見ると、ThreadクラスはRunnableインタフェースを実装していることがわかります.
public
class Thread implements Runnable {
…
/* What will be run. */
private Runnable target; // target runnable
/* The group of this thread */
private ThreadGroup group;
…
public Thread(Runnable target) {//
init(null, target, "Thread-" + nextThreadNum(), 0);
}
}
Threadクラスのstart()メソッドを呼び出すと、ローカルメソッドstart 0()が呼び出されます.
public synchronized void start() {
……
boolean started = false;
try {
start0();
started = true;
} finally {
……
}
}
private native void start0();
要するにrunメソッドに呼び出されます.
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
Runnableを使用してThreadを構築すると、Runnableオブジェクトのrunメソッドが呼び出されます.さもないと、何もしません.しかし,継承方式でスレッドを実現すると,Threadクラスのrunメソッドは多態でまったく実行されないため,書き換えrunメソッドが実行される.
たとえば,Threadから引き継いでrunメソッドを実装し,RunnableによってThread結果を構築するとどのrunメソッドが実行されるのか.答えは確定です.Threadクラスから継承されたrunメソッドが実行されます.
class MyRunnable implements Runnable{
public void run() {
System.out.println("MyRunnable");
}
}
class MyThread extends Thread{
public MyThread(Runnable r){
super(r);
}
public void run() {
System.out.println("MyThread");
}
}
class Test{
public static void main(String[] args) {
Thread t = new MyThread(new MyRunnable());
t.start();
}
}
// output:
//MyThread
いったいThreadを使うのか、それともRunnableを使うのか.
Runnableインタフェースを実装することは、Threadクラスを継承することよりも優れています.
1.同一のプログラムコードが複数あるスレッドに適合して同一のリソースを処理し、Threadを継承する必要がある共有リソースをstaticに設定する.
2.javaでの単一継承の制限を回避
3.プログラムの堅牢性を高め、コードは複数のスレッドで共有でき、コードとデータは独立している.
最初のコードのcountフィールドをstaticに変更
class MyThread extends Thread{
private static int count;// static
public MyThread(String id){
super(id);
}
public void run() {
while (count < 5) {
count ++;
System.out.println(currentThread() + "--->" + count);
}
}
}
class Test{
public static void main(String[] args) {
Thread t1 = new MyThread("thread_1");
Thread t2 = new MyThread("thread_2");
t1.start();
t2.start();
}
}
// output ( )
//Thread[thread_1,5,main]--->2
//Thread[thread_2,5,main]--->2
//Thread[thread_2,5,main]--->3
//Thread[thread_2,5,main]--->4
//Thread[thread_2,5,main]--->5
staticを使用してもリソースを共有しても、Threadを作成したRunnableオブジェクトが同じであることを前提として、2番目の方法でマルチスレッドを実装してもよいことがわかります.
注意深く見ると、印刷の構造は私たちが予想していたものではありません.例えば、
//Thread[thread_1,5,main]--->2
//Thread[thread_2,5,main]--->2
このような結果が出たのは,マルチスレッド同時の制御不能性のためであり,スレッド同期については後述する.