スレッドとプロセス
プロセスはプログラムの動的実行プロセスであり、コードのロードと実行から実行の完了までの完全なプロセスを経ています。このプロセスは、プロセス自体の生成、開発から最終的な終了までのプロセスでもあります。
スレッドはプロセスよりも小さな実行単位です。スレッドはプロセスに基づいてさらに分割されます。プロセスには、同時に実行される複数のスレッドが含まれる場合があります。
注:すべてのスレッドがプロセスにアタッチされている必要があります。プロセスが非表示になると、スレッドも非表示になります。Javaは、マルチスレッドをサポートする数少ない開発言語の1つです。
マルチスレッド実装
Javaでは、マルチスレッドプログラムを実装する場合、スレッドのメインボディ(スレッドのメインクラスを表す)に依存する必要があります。ただし、このスレッドのメインクラス本体には、定義時にいくつかの特別な要件が必要です。つまり、このクラスは、Threadクラスを継承するか、Runnable(Callable)インターフェイスを実装して定義を完了する必要があります。
スレッドクラスを継承する
java.lang.Threadは、スレッド操作を担当するクラスです。どのクラスも、スレッドのメインクラスになるためにThreadクラスを継承するだけで済みます。スレッドメインクラスの定義形式は以下のとおりです。
class 类名称 extends Thread{ //继承Thread类
属性...; //类中定义属性
方法...; //类中定义方法
public void run(){ //覆写Thread类中的run()方法,此方法是线程的主体
线程主体方法;
}
}
例:複数のスレッドを開始する
package Project.Study.Multithreading;
import java.lang.Thread;
class MyThread extends Thread{ //这就是一个多线程的操作类
private String name; //定义类中的属性
public MyThread(String name){ //定义构造方法
this.name=name;
}
@Override
public void run(){ //覆写run()方法,作为线程的主操作方法
for (int x=0;x<200;x++){
System.out.println(this.name+"-->"+x);
}
}
}
public class Test1 {
public static void main(String[] args){
MyThread mt1=new MyThread("线程A"); //实例化多线程对象
MyThread mt2=new MyThread("线程B");
MyThread mt3=new MyThread("线程C");
mt1.start(); //启动多线程
mt2.start();
mt3.start();
}
}
//结果
//线程B-->0
//线程C-->0
//线程A-->0
//线程C-->1
//线程B-->1
//线程C-->2
//后面省略...
注:run()メソッドを直接呼び出してもマルチスレッドは開始されません。マルチスレッドを開始する唯一の方法は、Threadクラスのstart()メソッドです:public void start()(このメソッドを呼び出すことによって実行されるメソッドの本体はrun()メソッド定義です)コード)
Runnableインターフェースを実装する
マルチスレッドを実現するためのThreadクラスの最大の欠点は、単一継承の問題であるため、JavaはRunnableインターフェースを使用してマルチスレッドを実現することもできます。このインターフェースは次のように定義されています。
@FunctionalInterface //函数式接口
public interface Runnable{
public void run();
}
例:Runnableを使用してマルチスレッドを実現する
package Project.Study.Multithreading;
class MyTread2 implements Runnable{ //定义线程主体类
private String name; //定义类中的属性
public MyTread2(String name){ //定义构造方法
this.name=name;
}
@Override
public void run(){ //覆写run()方法
for(int x=0;x<200;x++){
System.out.println(this.name+"-->"+x);
}
}
}
public class Test2 {
public static void main(String []args){
MyTread2 mt1=new MyTread2("线程A"); //实例化多线程类对象
MyTread2 mt2=new MyTread2("线程B");
MyTread2 mt3=new MyTread2("线程C");
new Thread(mt1).start(); //使用Thread启动多线程
new Thread(mt2).start();
new Thread(mt3).start();
}
}
//结果:
//线程C-->0
//线程A-->0
//线程B-->0
//线程A-->1
//线程C-->1
//线程C-->2
//后面省略...
例:Lambda式演算を使用する
package Project.Study.Multithreading;
public class Test2 {
public static void main(String []args){
String name="线程对象";
new Thread(()->{
for(int x=0;x<200;x++){
System.out.println(name+"-->"+x);
}
}).start();
}
}
//结果:
//线程对象-->0
//线程对象-->1
//线程对象-->2
//线程对象-->3
//线程对象-->4
//线程对象-->5
//后面省略...
呼び出し可能インターフェースを使用してマルチスレッドを実現する
Callableインターフェースは、Runnableインターフェースのrun()メソッドが操作結果を返すことができないという問題を解決します。
このインターフェースの定義は次のとおりです。
@FunctionalInterface
public interface Callable{
public V call() throws Exception;
}
スレッドボディクラスを定義する
import java.util.concurrent.Callable;
class MyThread3 implements Callable<String>{ //多线程主体类
private int ticket=10; //卖票
@Override
public String call() throws Exception{
for(int x=0;x<100;x++){
if(this.ticket>0){ //还有票可以出售
System.out.println("卖票,ticket="+this.ticket--);
}
}
return "票已卖光!"; //返回结果
}
}
マルチスレッドのメインクラスの定義が完了したら、スレッドクラスを使用してマルチスレッドを開始する必要がありますが、Callableインターフェイスオブジェクトインスタンスを直接受信するコンストラクターはThreadクラスで定義されていません。また、call()メソッドの戻り値を受信する必要があるため、 Javaは、次のように定義されたjava.util.concurrent.FutureTask <V>クラスを提供します。
public class FutureTask<V>
extends Object
implements RunnableFuture<V>
例:複数のスレッドを開始する
package Project.Study.Multithreading;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyThread3 implements Callable<String>{
private int ticket=10;
@Override
public String call() throws Exception{
for(int x=0;x<100;x++){
if(this.ticket>0){
System.out.println("卖票,ticket="+this.ticket--);
}
}
return "票已卖光!";
}
}
public class Test3 {
public static void main(String []args)throws Exception{
MyThread3 mt1=new MyThread3(); //实例化多线程对象
MyThread3 mt2=new MyThread3();
FutureTask<String>task1=new FutureTask<>(mt1);
FutureTask<String>task2=new FutureTask<>(mt2);
//FutureTask是Runnable接口子类,所以可以使用Thread类的构造来接收task对象
new Thread(task1).start(); //启动第一个多线程
new Thread(task2).start(); //启动第二个多线程
//多线程执行完毕后可以取得内容,依靠FutureTask的父接口Future中的get()方法实现
System.out.println("A线程返回的结果:"+task1.get());
System.out.println("B线程返回的结果:"+task2.get());
}
}
//结果:
//卖票,ticket=10
//卖票,ticket=9
//卖票,ticket=10
//卖票,ticket=9
//卖票,ticket=8
//卖票,ticket=8
//卖票,ticket=7
//卖票,ticket=7
//卖票,ticket=6
//卖票,ticket=6
//卖票,ticket=5
//卖票,ticket=5
//卖票,ticket=4
//卖票,ticket=4
//卖票,ticket=3
//卖票,ticket=2
//卖票,ticket=1
//卖票,ticket=3
//卖票,ticket=2
//卖票,ticket=1
//A线程返回的结果:票已卖光!
//B线程返回的结果:票已卖光!
このプログラムは、FutureTaskクラスを使用してCallableインターフェースのサブクラスを実装します。FutureTaskはRunnableインターフェースのサブクラスであるため、Treadクラスのstart()メソッドを使用してマルチスレッドを開始できます。スレッドの実行が完了すると、get( )メソッドはスレッドの実行結果を返します。
スレッドの動作状態
通常、どのスレッドにも5つの状態があります。つまり、作成、準備、実行、ブロック、終了です。
1.状態を作成する
構築メソッドを使用してプログラムでスレッドオブジェクトを作成した後、新しいスレッドオブジェクトは新しい状態になり、現時点では対応するメモリ領域とその他のリソースがありますが、まだ操作できない状態です。
2.準備完了状態
新しいスレッドオブジェクトを作成した後、スレッドのstart()メソッドを呼び出してスレッドを開始します。スレッドが開始すると、スレッドは準備完了状態になります。この時点で、スレッドはスレッドキューに入り、CPUサービスを待ちます。これは、スレッドがすでに実行状態にあることを示しています。
3.稼働状態
準備完了状態のスレッドが呼び出され、プロセッサリソースを取得すると、スレッドは実行状態になります。このとき、スレッドオブジェクトのrun()メソッドが自動的に呼び出されます。
4.ブロックされた状態
一時停止されている、または時間のかかる入出力操作を実行する必要があるなどの特定の状況下では、実行中のスレッドはCPUを放棄し、一時的にその実行を一時停止してブロック状態に入ります。実行可能状態で、sleep()、suspend()、wait()およびその他のメソッドを呼び出すと、スレッドはブロックされた状態になります。スレッドは輻輳するとキューイングキューに入ることができず、輻輳の原因が取り除かれた後でなければ、スレッドはレディ状態に移行できません。
5.終了ステータス
スレッドがstop()メソッドまたはrun()メソッドを呼び出すと、スレッドは終了状態になります。終了状態のスレッドは、実行を継続することができません。