Javaマルチスレッドの実装
コードを示すためにJavaマルチスレッドを実装する4つの方法
1つ目:Threadクラスメソッドを継承する
1.Runnableクラスを実装します2.run
メソッドを書き直し
ます3.スレッドオブジェクトを作成します4.start
メソッドを呼び出してスレッドを開始します
/**
* @ClassName RunnableDemo
* @Description TODO
* @Author Hai
* @Date 2020/12/12 11:29
* @Version 1.0
**/
//第一步:继承Thread
public class ThreadDemo extends Thread {
//票数
private static Integer ticketNums = 0;
@Override
//第二步:重写run方法
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println("当前正在运行子线程---第"+i+"次");
}
}
public static void main(String[] args){
//第三步:创建一个线程对象
ThreadDemo threadDemo = new ThreadDemo();
//第四步:调用start()启动线程
threadDemo.start();
for (int i = 0; i < 1000; i++) {
System.out.println("正在运行主线程---第"+i+"次");
}
}
}
クリックしてメインメソッドを実行し
ます。スレッドが開始されると、すぐには実行されませんが、CPUによって実行され
ます。2つのforループが並行して実行されていることがわかります。
注意!注意!
start()メソッドを呼び出してスレッドを開始し、run()メソッドを直接呼び出して開始するのは、通常の呼び出しメソッドと同じです。スレッドを開始することはできませんが、通常のメソッドを呼び出すだけの場合と同じです。
2番目の方法:Runnableインターフェースを実装する
1.Runnableインターフェースを実装します2.run
メソッドを書き直し
ます3.Threadオブジェクトを作成します4.start
メソッドを呼び出してスレッドを開始します
/**
* @ClassName RunnableDemo
* @Description TODO
* @Author Hai
* @Date 2020/12/12 11:29
* @Version 1.0
**/
//第一步:继承Thread
public class RunnableDemo implements Runnable{
//票数
private static Integer ticketNums = 0;
@Override
//第二步:重写run方法
public void run(){
while (true){
//一共一百张票,抢完则跳出循环
if(ticketNums>=100){
break;
}
//获取当前线程名称并输出
System.out.println(Thread.currentThread().getName()+"---拿到了第"+ ++ticketNums +"票");
}
}
public static void main(String[] args){
RunnableDemo runnableDemo = new RunnableDemo();
//第三步:创建Thread对象 (为方便理解,以下不采用简写)
Thread t1 = new Thread(runnableDemo ,"小明");
Thread t2 = new Thread(runnableDemo ,"小红");
Thread t3 = new Thread(runnableDemo ,"黄牛");
//第四步:调用start方法启动线程
t1.start();
t2.start();
t3.start();
}
}
クリックしてメインメソッドを実行し
ます。スレッドが開始されると、すぐには実行されませんが、CPUによってスケジュールおよび実行されます。
注意!注意!再度宣言するには:
start()メソッドを呼び出してスレッドを開始し、run()メソッドを直接呼び出して開始することは、通常の呼び出しメソッドと同じです。スレッドを開始することはできませんが、通常のメソッドを呼び出すだけと同じです。
3番目のタイプ:Callableインターフェースを実装する方法
1.Callableインターフェースを実装します2.call
()メソッドを書き直し
ます3.実行サービスを作成します
4.実行のために送信し
ます5.結果を取得し
ます6.サービスを閉じます
/**
* @ClassName CallableDemo
* @Description TODO
* @Author Hai
* @Date 2020/12/12 11:29
* @Version 1.0
**/
//第一步:实现Callable接口
public class CallableDemo implements Callable<Boolean> {
private String name;
public CallableDemo(String name) {
this.name = name;
}
//第二部:重写call()方法
@Override
public Boolean call() {
demo();
return true;
}
public void demo(){
for (int i = 0; i < 1000; i++) {
System.out.println("当前正在运行--"+ name +" 号线程--第"+i+"次");
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableDemo setname1 = new CallableDemo("小明");
CallableDemo setname2 = new CallableDemo("小红");
//第三步:创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(2);
//第四步:提交执行
Future<Boolean> t1 = ser.submit(setname1);
Future<Boolean> t2 = ser.submit(setname2);
//第五步:获取结果
Boolean b1 = t1.get();
Boolean b2 = t2.get();
//关闭服务
ser.shutdownNow();
System.out.println(b1);
System.out.println(b2);
}
}
クリックしてmainメソッドを実行し
ます。スレッドが開始されると、すぐには実行されませんが、CPUによってスケジュールおよび実行されます。
注意!注意!
start()メソッドを呼び出してスレッドを開始し、run()メソッドを直接呼び出して開始するのは、通常の呼び出しメソッドと同じです。スレッドを開始することはできませんが、通常のメソッドを呼び出すだけの場合と同じです。
覚えておいてください!覚えておいてください!
Callableインターフェースを実現してスレッドを作成します。スレッドが終了したら、スレッドサービスを閉じる必要があります。プログラムの例外が原因でサービスが閉じられないのを防ぐために、try / catchを使用してfinallyに入れるのが最善です。
次の図に示すように、複数のスレッドが同じデータを操作すると、スレッドのセキュリティが低下します。
このブログでは、主にマルチスレッドのいくつかの実装について説明しています。スレッドセーフについては後で説明します。
4番目:スレッドプールを使用して作成する
何为线程池,顾名思义线程池就是一个 专门存放线程的一个池子
提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回线程池中,这样可以避免频繁创建,销毁线程,实现重复利用。就像共享单车,当你使用完后别人还能使用
能提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程的管理(...)
corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间后会终止
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName TestPool
* @Description TODO
* @Author Hai
* @Date 2020/12/12 11:29
* @Version 1.0
**/
public class TestPool {
public static void main(String[] args) {
//3,创建服务,创建线程池
//newFixedThreadPool 参数为:线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//4,执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//5,关闭链接
service.shutdown();
}
}
//1,实现 Runnable接口
class MyThread implements Runnable{
//2,重写run方法编写线程体
@Override
public void run() {
//输出当前线程的名字
System.out.println(Thread.currentThread().getName());
}
}
直接実行メソッド
は、次のことを示しています。6つのスレッドが実行され、各スレッドの名前が正常に出力されます。
スレッドの作成を確認して要約する
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @ClassName TestPool
* @Description TODO
* @Author Hai
* @Date 2020/12/12 11:29
* @Version 1.0
**/
//回顾总结线程的创建
public class TheradNew {
public static void main(String[] args) {
//调用各个线程
//继承Thread类启动方法
new MyThread1().start();
//实现Runnable接口启动方法
new Thread(new MyThread2()).start();
//实现Callable接口启动方法
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
new Thread(futureTask).start();
try {
//不要忘了实现Callable接口方式创建线程会有返回值
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//1丶继承Thread类
class MyThread1 extends Thread{
@Override
public void run(){
System.out.println("继承Thread类创建线程");
}
}
//2丶实现Runnable接口
class MyThread2 implements Runnable{
@Override
public void run(){
System.out.println("实现Runnable接口创建线程");
}
}
//3丶实现Callable接口
class MyThread3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("实现Callable接口创建线程");
return 100;
}
}
スレッドを作成するための非常に多くの方法を学んだ後、どれが最良ですか?
現時点では、この質問に対する正確な答えはありません。さまざまな方法にはそれぞれ長所と短所があります。さまざまなアプリケーションシナリオに応じてさまざまな作成方法を使用するのが最適です。同時実行性が比較的高い場合、スレッドプールの作成は次のようになります。より適切です。事前に複数のスレッドを作成し、それらをスレッドプールに入れ、使用時に直接取得し、使用後にスレッドプールに戻すことができるため、リソースに影響を与えるスレッドの頻繁な作成と破棄を回避できます。効率を高め、再利用を実現します。もちろん、これは並行性が比較的高い特定のシナリオにすぎず、スレッドプールを作成する方法が最適であるとは言えません。これには、読者がアプリケーションシナリオとさまざまな作成方法の理解に基づいて独自の決定を行う必要があります。最善の方法はなく、最も適切な方法のみです。