Java 4種類のマルチスレッド作成:
- プログラムとは?
- プロセスとは何ですか?
- スレッドとは?
- 並列および同時:
- 次に、JAVAマルチスレッド実装:
- (1)マルチスレッドを実現するためにThreadクラスを継承します:
- (2)マルチスレッドを実現するためにRunnableインターフェースを実装します。
- (3)呼び出し可能なメソッドを実装する:(Runnableメソッドを実装するよりも強力)
- (4)ExecutorService、Future(スレッドプール)を使用して、マルチスレッドの戻り結果を取得します。
- スレッドプールモードのコードの説明:
- 概要:4種類のスレッドの作成と、スレッドの簡単な紹介です。他にご不明な点がございましたら、お気軽にお問い合わせください。
プログラムとは?
- プログラム:特定のタスクを実行するために特定の言語で記述された一連の命令。静的コードを指します。
プロセスとは何ですか?
- プロセス:プログラム、または実行中のプログラムを実行するプロセス。
- 注: プロセスはリソース割り当ての単位であり、システムの実行中、システムはプロセスごとに異なるメモリ領域を割り当てます。
スレッドとは?
- スレッド:プロセスは、プログラム内の実行パスであるスレッドにさらに改良できます。
- 注: スレッドはスケジューリングと実行の単位であり、各スレッドには独立した実行スタックとプログラムカウンター(pc)があり、スレッド切り替えのオーバーヘッドはわずかです。
並列および同時:
-
並列: 複数のCPUが複数のタスクを同時に実行します。たとえば、複数の人が同時に異なることをします。
-
同時実行性: CPU(タイムスライスを使用)は、複数のタスクを同時に実行します。複数のスレッドが動作しているときに、システムにCPUが1つしかない場合、複数のスレッドを同時に実際に実行することは不可能であり、CPUの実行時間をいくつかの期間に分割して、その期間を各スレッドに割り当てることができます。実行。スレッドコードが一定期間実行されている場合、他のスレッドは中断状態です。これは並行性です
次に、JAVAマルチスレッド実装:
JAVAマルチスレッドを実現するには、主に3つの方法があります。Threadクラスを継承し、Runnableインターフェースを実装し、ExecutorService、Callable、およびFutureを使用して、結果を返すマルチスレッドを実現します。スレッド実行の最初の2つの方法の後は戻り値はなく、最後の1つだけが戻り値を持っています。
(1)マルチスレッドを実現するためにThreadクラスを継承します:
- Threadクラスを継承するメソッドはマルチスレッド実装メソッドとしてリストされていますが、Threadは本質的にはRunnableインターフェースのインスタンスであり、スレッドのインスタンスを表し、スレッドを開始する唯一の方法はThreadクラスの開始を経由することです()メソッドの例。start()メソッドは、新しいスレッドを開始してrun()メソッドを実行するネイティブメソッドです。この方法でマルチスレッドを実装するのは非常に簡単です。独自のクラスを介してThreadを直接拡張し、run()メソッドを上書きして新しいスレッドを開始し、独自のrun()メソッドを実行できます。
- Threadクラスから継承されたサブクラスを作成する
- Threadクラスのrun()を書き換えます-> run()でこのスレッドによって実行される操作を宣言します
- Threadクラスのサブクラスのオブジェクトを作成する
- **このオブジェクトを介してstart()を呼び出します**
public class ThreadTest extends Thread{ //创建一个继承于Thread类的子类
//重写Thread类的run() --> 将此线程执行的操作声明在run()中
@Override
public void run(){
System.out.println("这是:[" + getName() + "]的启动");
}
public static void main(String[] args) {
//创建Thread类的子类的对象
ThreadTest thread1 = new ThreadTest();
ThreadTest thread2 = new ThreadTest();
thread1.setName("线程一");//给线程设置名字
thread2.setName("线程二");
thread1.start();//通过线程子类对象调用start()
thread2.start();
}
}
コンソールの結果:
这是:[线程一]的启动。
这是:[线程二]的启动。
Process finished with exit code 0
可知启动了两个线程
(2)マルチスレッドを実現するためにRunnableインターフェースを実装します。
- 独自のクラスがすでに別のクラスを拡張している場合、Threadを直接拡張することはできません。この場合、Runnableインターフェースを実装する必要があります。
-
Runnableインターフェースを実装するクラスを作成する
-
Runnableで抽象メソッドを実装するための実装クラス:run()
-
クラスを実装するオブジェクトを作成する
-
このオブジェクトをパラメーターとしてThreadクラスのコンストラクターに渡して、Threadクラスのオブジェクトを作成します
-
クラスThreadのオブジェクトを介してstart()を呼び出す
//创建一个实现了Runnable接口的类
public class RunnableStart extends Thread implements Runnable {
//实现类去实现Runnable中的抽象方法:run()
@Override
public void run() {
System.out.println("这是:[" + Thread.currentThread().getName() + "]的启动");
}
public static void main(String[] args) {
// 创建实现类的对象
RunnableStart runnableThread = new RunnableStart();
// 将实现类对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread thread1 = new Thread(runnableThread);
Thread thread2 = new Thread(runnableThread);
thread1.setName("Runnable方式线程一:");//设置线程的名字
thread2.setName("Runnable方式线程二:");
// 通过Thread类的对象调用start()
thread1.start();
thread2.start();
}
}
コンソール出力:
这是:[Runnable方式线程二:]的启动
这是:[Runnable方式线程一:]的启动
Process finished with exit code 0
**注:**実際、Runnableターゲットパラメータがスレッドに渡されると、スレッドのrun()メソッドはtarget.run()を呼び出します。JDKソースコードを参照してください。
public void run() {
if (target != null) {
target.run();
}
}
(3)呼び出し可能なメソッドを実装する:(Runnableメソッドを実装するよりも強力)
Callableインターフェースを実装してマルチスレッドを作成する方法は、Runnableインターフェースを実装してマルチスレッドを作成する方法よりも強力であることをどのように理解しますか?
- call()は戻り値を持つことができます。
- call()は例外をスローし、外部の操作によってキャッチされて、例外情報を取得できます。
- Callableはジェネリックをサポートします
- Callableを実装する実装クラスを作成する
- callメソッドを実装し、このスレッドがcall()で実行する必要がある操作を宣言します
- Callableインターフェイス実装クラスオブジェクトを作成する
- このCallableインターフェース実装クラスのオブジェクトをFutureTaskコンストラクターに渡して、FutureTaskのオブジェクトを作成します
- FutureTaskオブジェクトをパラメーターとしてThreadクラスのコンストラクターに渡し、Threadオブジェクトを作成して、start()を呼び出します
- Callableでcallメソッドの戻り値を取得します
//1.创建一个实现Callable的实现类
class CallThread implements Callable {
//2.实现call方法,将此线程需要执行的操作声明在call()中
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
sum += i;//计算100以内偶数之和
}
}
return sum;
}
}
public class ThreadTest {
public static void main(String[] args) throws Exception {
//3.创建Callable接口实现类的对象
CallThread callThread = new CallThread();
//4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
FutureTask futureTask = new FutureTask(callThread);
//5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
Thread thread = new Thread(futureTask);
thread.start();
//6.获取Callable中call方法的返回值
//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
Object sum = futureTask.get();
System.out.println("实现Callable方式的返回值总和为:" + sum);
}
}
コンソールの結果:
实现Callable方式的返回值总和为:2550
Process finished with exit code 0
(4)ExecutorService、Future(スレッドプール)を使用して、マルチスレッドの戻り結果を取得します。
方法:
- スレッドプールを作成する
- 戻り値を持つ複数のタスクを作成する
- タスクを実行し、Futureオブジェクトを取得する
- スレッドプールを閉じる
public class ThreadPoolTest {
public static void main(String[] args) throws Exception {
System.out.println("----程序开始运行----");
Date start = new Date();//开始时间
// 创建一个指定数量的线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
// 创建多个有返回值的任务
List<Future> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {//因为只设有限定10个线程
Callable call = new TestCallable(i + " ");
// 执行任务并获取Future对象
Future f = pool.submit(call);
list.add(f);
}
// 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从Future对象上获取任务的返回值,并输出到控制台
System.out.println(">>>" + f.get().toString());
}
Date end = new Date();//结束时间
System.out.println("----程序结束运行----,程序运行时间【"
+ (end.getTime() - start.getTime()) + "毫秒】");//计算出来的总运行时间
}
}
class TestCallable implements Callable<Object> {
private String taskNum;//任务编号
TestCallable(String taskNum) {
this.taskNum = taskNum;
}
@Override
public Object call() throws Exception {
System.out.println(">>>" + taskNum + "任务启动");
Date dateStart = new Date();//开始时间
Thread.sleep(1000);//阻塞1000毫秒
Date dateEnd = new Date();//结束时间
long time = dateEnd.getTime() - dateStart.getTime();
System.out.println(">>>" + taskNum + "任务终止");
return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
}
}
コンソールの結果:
----程序开始运行----
>>>0 任务启动
>>>3 任务启动
>>>2 任务启动
>>>1 任务启动
>>>4 任务启动
>>>5 任务启动
>>>6 任务启动
>>>8 任务启动
>>>7 任务启动
>>>9 任务启动
>>>4 任务终止
>>>2 任务终止
>>>1 任务终止
>>>3 任务终止
>>>5 任务终止
>>>0 任务终止
>>>0 任务返回运行结果,当前任务时间【1001毫秒】
>>>1 任务返回运行结果,当前任务时间【1001毫秒】
>>>2 任务返回运行结果,当前任务时间【1001毫秒】
>>>3 任务返回运行结果,当前任务时间【1001毫秒】
>>>4 任务返回运行结果,当前任务时间【1001毫秒】
>>>5 任务返回运行结果,当前任务时间【1001毫秒】
>>>8 任务终止
>>>6 任务终止
>>>7 任务终止
>>>6 任务返回运行结果,当前任务时间【1001毫秒】
>>>7 任务返回运行结果,当前任务时间【1001毫秒】
>>>9 任务终止
>>>8 任务返回运行结果,当前任务时间【1001毫秒】
>>>9 任务返回运行结果,当前任务时间【1001毫秒】
----程序结束运行----,程序运行时间【1005毫秒】
スレッドプールモードのコードの説明:
著者からのコード説明は:不可解な今日見wb_qiuquan.ying。
上記のコードのExecutorsクラスは、スレッドプールを作成するための一連のファクトリメソッドを提供し、返されたスレッドプールはすべてExecutorServiceインターフェイスを実装します。
public static ExecutorService newFixedThreadPool(int nThreads)
は、固定数のスレッドでスレッドプールを作成します。
public static ExecutorService newCachedThreadPool()
はキャッシュ可能なスレッドプールを作成し、executeを呼び出すと、以前に構築されたスレッドが再利用されます(スレッドが利用可能な場合)。利用可能な既存のスレッドがない場合、新しいスレッドが作成され、プールに追加されます。60秒間使用されなかったスレッドを終了して削除します。
public static ExecutorService newSingleThreadExecutor()
はシングルスレッドのExecutorを作成します
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
は、スケジュールされた定期的なタスク実行をサポートするスレッドプールを作成し、ほとんどの場合、Timerクラスを置き換えるために使用できます。
ExecutoreServiceはsubmit()メソッドを提供し、CallableまたはRunnableを渡し、Futureを返します。ExecutorバックグラウンドスレッドプールがCallableの計算をまだ完了していない場合、この呼び出しはFutureオブジェクトのget()メソッドを返し、計算が完了するまでブロックします。