Javaの---(理論からプログラミングまで)マルチスレッド

コンセプト

図1は、プログラム:いくつかの部分からなる特定の機能を有するステップ及び命令のシーケンス解く
2のプロセス:プログラムの実行は、リソース割り当ての最小単位である
CPUの基本的なスケジューリング単位:3、スレッド

コメントは良いの下で説明しました

非常に良い話があります

技術的な詳細のすべての種類にもかかわらず、アプリケーションの観点から:

==
1、シングルコアコンピュータありリソースは、並列複数のプログラムで使用することができませんの:CPU。
いかなる状況下では、オペレーティングシステムプログラムは、すべてのCPUとの排他的となっています
あなたが同じCPUを共有するための2つのタスクを持っている場合は、プログラマのニーズは慎重にプログラムを実行するためのプログラムのために配置される-タイムCPUと排他的にプログラムによるプログラムA、B、次回のCPUへの排他的
かつこの配置計画では、後に"、すなわち、「スケジューラ」に任命され、個々の名前であるOSのコアコンポーネントになりましたスケジューラ「実行シート「それだけのセクションに分割された単一のCPUを実行する方法に関するものです」替わります使用する別のプログラムに割り当てられ、そして高いレベルで、高速スイッチング速度分布ので、アーチファクトのCPU上で並列プログラムを複数生成します。

図2に示すように、シングルコア・コンピュータ、共有リソースがあるが、しかし、複数のプログラムであってもよいですトラブルにつながる:メモリを
唯一のスケジューラ、無メモリー管理コンポーネントのオペレーティングシステムでは、プログラマは手動で各プログラムの実行のためのスペースを配置する必要がある-物理アドレス0x00-0xffプログラム、物理アドレス0x100-0x1FF手順B、などが挙げられます。
そう、しかし大きな問題があります:メモリを別の領域を使用する方法について良い議論を調整するすべてのプログラムは、システムソフトウェアおよびハードウェアのシステムが大きく異なるので、このカスタマイズされたプログラムは実行可能ではありません。

このトラブルを解決するために、コンピュータ・システムは、 "紹介します仮想アドレス「コンセプトは、三つの側面から開始します:

責任2.1、ハードウェア、CPUはMMUと呼ばれる特別なモジュールを追加し、仮想アドレスと物理的にサイト。

2.2、オペレーティングシステム、あるメモリ管理、:オペレーティングシステムは、他のコアコンポーネントを追加しますメモリ管理モジュールこれは、物理メモリ、取引の仮想メモリ関連のシリーズを管理します。

用途に、本発明が呼び出される2.3、[プロセス]モデル(注==)各プロセスは正確[]仮想アドレス空間と同じであるが、オペレーティング・システムおよびハードウェアMMUコラボレーションを通して、異なる物理アドレス空間にマッピング==。[別の]プロセスは、自分自身を持っています物理メモリの独立スペースは、いくつかの特別な手段なしに、別のプロセスの物理メモリにアクセスすることができません。

3、今、異なるアプリケーションシーケンスは、基礎となる物理メモリの割り当てを気に、またはCPUを共有するコーディネートを気にしないかもしれません。しかし、一つ問題があります:いくつかのプログラムがありますが、私は、共有CPUにしたいです、[とも]同じ物理メモリ、今回、という男を共有します[スレッド]モデルに、しかし、彼らはプロセスで過去ラップ自分自身を取得することはできません、同じ仮想アドレス空間で、管理スケジューラの下で、彼らはプロセス内にラップされた、共有CPUが登場するだけでなく、同一の物理アドレス空間を共有しますプロセスの物理アドレス空間をアクセスしないでください。

4、どのようにプロセスのそれとの間に同一の物理アドレス空間を共有するには?mmapと呼ばれるインタフェースを提供し、さまざまな方法で異なるシステムは、POSIX標準のオペレーティングシステムに合わせて、あなたは別のプロセスによって共有異なるプロセス、物理アドレス空間にマッピングすることができます。

図5に示すように、PS:いくつかのオペレーティングシステムでは、処理ユニットをスケジューリングされていないスレッドがスケジューリングの基本単位である、(すなわち、スケジューラによって使用することができない)、例えばVxWorksのようなだけではなく、スケジューリングプロセススケジューラのスケジュールスレッド、

ライフサイクルのスレッド

  • 新しい状態:

スレッドオブジェクトと新しいキーワードThreadクラスまたはサブクラスを確立した後、スレッドは、オブジェクトの新しい状態です。これは、プログラム開始()このスレッドになるまでこの状態のままになります。

  • レディ状態:

スレッドオブジェクトは、start()メソッド、レディ状態にスレッドを呼び出すとき。レディキューで準備完了スレッドは、JVMのスレッドスケジューラをスケジュールする待っています。

  • 動作状態:

スレッドがCPUリソースの準備状態を取得する場合は、実行を行うことができます()、スレッドがこの時点で実行されます。最も複雑を実行中のスレッド、それがブロックされた状態、レディ状態、および死の状態になることができます。

  • 状態をブロックします:

スレッドがスリープ(スリープ)の後に実行されている場合は、一時停止(保留)および他の方法は、占有リソースの損失は、スレッドが実行されているからブロックされた状態になります。睡眠時間では機器やリソースがレディ状態を再入力することがあり得るようになってきました。これは3つのタイプに分けることができます:

ブロックを待っている:実行スレッドが待ちの状態()メソッドを実行し、スレッドは状態に入るのを待ってブロックされています。

同期ブロック:(別のスレッド同期ロックが占有されているため)同期スレッド同期ロックの失敗を取得します。

他のブロッキング:I / O要求を発行し、スレッドが()を呼び出すスレッドの睡眠を(ブロックすることにより、状態に入る)か、参加します。睡眠()タイムアウト、終了するスレッドの参加()待機またはタイムアウト、またはI / O処理が再びレディ状態に、スレッドを終了しました。

  • 死のステータス:

タスク又は他の終了条件発生のスレッドの動作状態は、スレッドは終了状態に切り替えられます。

スレッドの優先順位

優先度の高いスレッドはプログラムにとってより重要である、と前に優先順位の低いスレッドにプロセッサリソースを割り当てる必要があります。しかし、注文は実行のスレッドの優先順位のスレッドを保証するものではありませんが、また、プラットフォームに非常に依存。

これは良い紹介です

スレッドの優先順位は、唯一の理論的優先事項である、それは優先度の高いスレッドが最初の実行のわずかに大きい確率であってもよいことができ、しかし、スレッドの実行は、コンピュータによって制御される特定。我々はすべて知っているように、実行スレッドのためのコンピュータが実行誰でもつかむことができ先制戦略、であるので、このプログラムは完全に順序を制御することはできません。

一部からの質問と回答

1、高い優先順位は何かが最も優先度の高い操作よりも優先させることでなければならないことを意味するものではありません。そうでなければ、何の意味がマルチスレッド化しないように。
同じ条件の下で確率が、私は、仮想マシンの政策を見て、どのように特定の割り当てのように、下よりも高い優先順位を実行することを優先度の高い手段。しかし、確かではない、あなたがそれを望むように、優先度の高い実行彼らは低い優先順位を実行が終了するまで、

2は、すべて、最初のスレッドの優先度は、高い優先度がより多くのCPU時間を割り当てる保証するものではありません、最初に実行高い優先度を保証するものではありませんが、それは最後のランで、オペレーティングシステムによって決定されたシステムのために推奨されましたJavaは最終決定権はありません。
加算Javaで唯一の保証は、それは、このコーディングは、ご注文に合わせて行われるからと思われることを保証することはできません内部スレッドと他のスレッドでコードの実行順序であるように思わできます。

3、Java言語仕様、プログラムの正しさと性能の保証に応じて、我々は優先順位を頼ることはできません。
自分の制御プログラムに依存しています。
優先順位は、一般的に不足し、システムリソースの下にこの事はより明白かもしれません。
最適化の後、このを通じて少しあなたを実行します。
そうではないマニフェスト。

スレッドを作成します。

Javaはスレッドを作成するには、3つの方法が用意されています。

  • 、Runnableインタフェースを実装することにより、
  • 継承Threadクラス自体を通じ、
  • 呼び出し可能と未来を通じてスレッドを作成します。

、Runnableインタフェースを実装することで、スレッドを作成するには

class RunableDemo implements Runnable{
	
	private Thread t;
	private String name;
	
	RunableDemo(String name){
		
		this.name = name;
		System.out.println("create:"+this.name);
		
	}
	
	public void run(){
		int i;
		try{
			for(i=4;i>0;i--){
			System.out.println("run Thread:"+this.name+","+i);
			System.out.println("sleep:"+this.name+","+i);
			Thread.sleep(50);
			
			}
		}catch(InterruptedException e){
			
			System.out.println("interrupted:"+name);
		}
		
		System.out.println("exiting:"+this.name);
			
	}
	
	public void start(){
		
		System.out.println("--------");
		System.out.println("Thread start:"+this.name);
		if(t==null){
			t = new Thread(this,name);//创建名为name的thread
			t.start();//不是上面的start();
		}
	}
}


public class ThreadTest{

	public static void main(String[] args){
		
		RunableDemo r1 = new RunableDemo("gyy1");
		//r1.t = new Thread("gyy1");//错误,不能访问private
		
		r1.start();
		
		RunableDemo r2 = new RunableDemo("gyy2");
		
		
		r2.start();
	}
}

結果:第一の端部がgyy1こと、それが第一の端部をgyy2ことがあります。

E:\java_code\code>java ThreadTest
create:gyy1
--------
Thread start:gyy1
create:gyy2
--------
run Thread:gyy1,4
Thread start:gyy2
sleep:gyy1,4
run Thread:gyy2,4
sleep:gyy2,4
run Thread:gyy1,3
run Thread:gyy2,3
sleep:gyy1,3
sleep:gyy2,3
run Thread:gyy1,2
sleep:gyy1,2
run Thread:gyy2,2
sleep:gyy2,2
run Thread:gyy2,1
run Thread:gyy1,1
sleep:gyy2,1
sleep:gyy1,1
exiting:gyy2
exiting:gyy1

継承のスレッドを通じてスレッドを作成するには

//class RunableDemo implements Runnable{

class RunableDemo extends Thread{	
	private Thread t;
	private String name;
	
	RunableDemo(String name){
		
		this.name = name;
		System.out.println("create:"+this.name);
		
	}
	
	public void run(){
		int i;
		try{
			for(i=4;i>0;i--){
			System.out.println("run Thread:"+this.name+","+i);
			System.out.println("sleep:"+this.name+","+i);
			Thread.sleep(50);
			
			}
		}catch(InterruptedException e){
			
			System.out.println("interrupted:"+name);
		}
		
		System.out.println("exiting:"+this.name);
			
	}
	
	public void start(){
		
		System.out.println("--------");
		System.out.println("Thread start:"+this.name);
		if(t==null){
			t = new Thread(this,name);//创建名为name的thread
			t.start();//不是上面的start();
		}
	}
}


public class ThreadTest{

	public static void main(String[] args){
		
		RunableDemo r1 = new RunableDemo("gyy1");
		//r1.t = new Thread("gyy1");//错误,不能访问private
		
		r1.start();
		
		RunableDemo r2 = new RunableDemo("gyy2");
		
		
		r2.start();
	}
}

プログラム

1、デジタル入力キーボード、デジタルコンピュータは、そうでなければ停止し、等しくない場合にサイクルが継続入力と同じであるかどうかを周期的に乱数を与えます。


import java.util.Scanner;
class GuessTest extends Thread{
	
	private int number;
	GuessTest(int number){
		
		this.number = number;
		System.out.println("number:"+this.number+",yes or not?");
	}
	
	public void run(){
		
		int guess;
		int count=0;
		
		do{
			guess =(int)(Math.random()*100+1);
			System.out.println(this.getName()+" guess:"+guess);
			count++;
			
		}while(guess!=this.number);
			
		System.out.println("okok!yes:"+this.getName()+":guess:"+guess+",count:"+count);;
	}
}
public class GuessNumber{

	
	public static void main(String[] args){
		
		int i=0;
		Scanner s = new Scanner(System.in);
		System.out.println("请输入你的预测数字(整数):");
		
		
		
		if(s.hasNextInt()){
			
			i = s.nextInt();
			
			System.out.println("输入整数:"+i);
		}else{
			System.out.println("输入的不是整数。");
		}
		
		GuessTest g = new GuessTest(i);
		g.start();
		
	}
}

方法および各々がスレッドの実行:2、マルチスレッドの方法を使用して

//需要Thread与start
//采用Runnable接口

public class DisplayMessage implements Runnable{
	
	private String mge;
	
	DisplayMessage(String mge){
		
		this.mge = mge;
	}
	
	public void run(){
		
		System.out.println(mge);
		System.out.println(mge);
		// while(true){
			
			// System.out.println(mge);
		// }
	}
}

//采用Thread类
class GuessANumber extends Thread{
	
	private int number;
	GuessANumber(int number){
		
		this.number = number;
		System.out.println("number:"+this.number+",yes or not?");
	}
	
	public void run(){
		
		int guess;
		int count=0;
		
		do{
			guess =(int)(Math.random()*100+1);
			System.out.println(this.getName()+" guess:"+guess);
			count++;
			
		}while(guess!=this.number);
			
		System.out.println("okok!yes:"+this.getName()+":guess:"+guess+",count:"+count);;
	}
}



public class ThreadClassDemo{
	
	public static void main(String[] args){
		
		// //Runnable
	  // Runnable hello = new DisplayMessage("Hello");
      // Thread thread1 = new Thread(hello);
      // thread1.setDaemon(true);
      // thread1.setName("hello");
      // System.out.println("Starting hello thread...");
      // thread1.start();
		
		
		DisplayMessage r1 = new DisplayMessage("gyy1");
		Thread th1 = new Thread(r1);
		th1.setDaemon(true);
		System.out.println("start "+th1.getName()+" Thread……");
		th1.setName("ggyy1");
		System.out.println("start "+th1.getName()+" Thread……");
		th1.start();//打印的是mge不是name
		
		
		Runnable r2 = new DisplayMessage("gyy2");
		Thread th2 = new Thread(r2);
		th2.setPriority(Thread.MIN_PRIORITY);
		th2.setDaemon(true);
		System.out.println("start "+th2.getName()+" Thread……");
		th2.start();
		
		//Thread
		GuessANumber g1 = new GuessANumber(9);
		System.out.println("Starting "+g1.getName()+"...");
		g1.start();
		
		try{//去掉会使得可能g2先执行。
			g1.join();
		}catch(InterruptedException e){
			System.out.println("Thread interrupted.");
		}
		GuessANumber g2 = new GuessANumber(17);
		System.out.println("Starting "+g2.getName()+"...");
		g2.start();
		
		
		System.out.println("main() is ending...");
		
	}
}

3、スレッドの実行順序となるよう

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadDemo3{
	
	public static void main(String[] args){
		
		method3();
	}
	
	private static void method3(){
		
		final Thread t1 = new Thread(new Runnable(){
			@Override
			public void run(){
				System.out.println("111");
			}
		});
		
		final Thread t2 = new Thread(new Runnable(){
			@Override
			public void run(){
				System.out.println("222");
			}
		});
		
		final Thread t3 = new Thread(new Runnable(){
			@Override
			public void run(){
				System.out.println("333");
			}
		});
		
		//创建一个newSingleThreadExecutor的线程池
		ExecutorService ss = Executors.newSingleThreadExecutor();
		//队列,先进先出
		ss.submit(t1);
		ss.submit(t2);
		ss.submit(t3);
		ss.shutdown();
		
		
		
		
	}
}

呼び出し可能と未来を通じてスレッドを作成します。

呼び出し可能インターフェースの実装クラスを作成し、clall()メソッドを達成。そして、スレッドを作成するには、対象ThreadオブジェクトとしてFutureTaskクラス呼び出し可能ラッパーオブジェクトの実装クラスを使用しており、このFutureTaskのオブジェクトに。

具体的に:

  1. 実行、および戻り値のスレッドとして呼び出し可能インタフェースの実装クラスを作成し、器具()メソッドの呼び出し、呼び出し()メソッド。
  2. ()メソッドの呼び出しの戻り値のFutureTask呼び出し可能オブジェクトをカプセル化するオブジェクトパッケージ呼び出し可能FutureTaskクラスオブジェクトを使用して、実装クラスのインスタンスを作成して呼び出し可能。
  3. ターゲット・オブジェクトとして使用FutureTaskスレッドオブジェクトが作成し、新しいスレッドを開始します。
  4. コールFutureTaskオブジェクトのget()メソッドは、サブスレッド実行の終了後、戻り値を取得します。
//采用Callable和Future创建线程

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class CallableDemo implements Callable<Integer>{//创建Callable接口的实现类
	
	public static void main(String[] args){
		
		int i;
		
		CallableDemo cc = new CallableDemo();//创建Callable接口的实现类的对象
		
		FutureTask<Integer> ff = new FutureTask<Integer>(cc);//用FutureTask来包装Callable对象
		
		for(i=0;i<100;i++){
			
			System.out.println("线程:"+Thread.currentThread().getName()+"i的值:"+i);
			
			if(i==20){
				Thread tt = new Thread(ff,"gyy");//Future对象创建线程
				tt.start();
			}
			
		}
		System.out.println("循环结束");
		
		try{
			System.out.println("线程返回值:"+ff.get());//返回call里的返回值
		}catch(InterruptedException e){
			e.printStackTrace();
		}catch(ExecutionException e){
			e.printStackTrace();
		}
		
		
		
	}
	
	
	
	//call返回值
	@Override
	public Integer call() throws Exception{
		int j;
		for(j=0;j<100;j++){
			
			System.out.println("线程:"+Thread.currentThread().getName()+"j值:"+j);
		}
		return j;
		
	}
}


エラー:

E:\java_code\code>javac CallableDemo.java
CallableDemo.java:31: 错误: 找不到符号
                }catch(ExecutionException e){
                       ^
  符号:   类 ExecutionException
  位置: 类 CallableDemo
1 个错误

ソリューション:

将 ExecutionException 改成 Exception

スレッドを作成するための3つの方法の比較

  1. Runnableを、呼び出し可能インターフェース手段、Threadクラスの実装、Runnableインタフェースまたは単に呼び出し可能インターフェースを実現するために複数のスレッドを作成して使用する場合、あなたはまた、他のクラスから継承することができます。
  2. あなたは、準備するための簡単なマルチスレッド使用の継承Threadクラスを作成するときは、現在のスレッドにアクセスする必要がある場合、あなたは現在のスレッドを取得するためにThread.currentThread()メソッド、直接使用これを使用する必要はありません。

スレッドのいくつかの主要な概念

マルチスレッドプログラミングでは、次の概念を理解する必要があります。

スレッド同期

スレッド間通信

スレッドのデッドロック

スレッド制御:一時停止、停止と再開

複数のスレッドを使用して

マルチスレッドの有効活用の鍵は、プログラムを理解することで同時に実行ではなく連続的に実行されます。たとえば:2つのサブプログラムが同時実行を必要としますが、マルチスレッドプログラミングの利点を取る必要があり、この時があります。

複数のスレッドを使用することにより、あなたは非常に効率的なプログラムを書くことができます。しかし、あなたはあまりにも多くのスレッドを作成した場合、プログラムの実行の効率が実際に減少し、よりもむしろ増強されることをメモしてください。

コンテキストの切り替えは、オーバーヘッドあなたはあまりにも多くのスレッドを作成した場合、CPU時間は、プログラムの実行よりもコンテキストスイッチング時間に費やし、また非常に重要であり、覚えておいてください!

公開された12元の記事 ウォンの賞賛1 ビュー110

おすすめ

転載: blog.csdn.net/weixin_43351473/article/details/104415656