ディレクトリ
Javaの並行処理(A)---マルチスレッドスターター
1、基本的な考え方
1.1、プロセスとスレッド
- プロセスは:システムがプロセスの終焉に作成から、プロセスをあるプログラムを実行して、プログラムです。
- スレッド: 360再度ゴミ、再びアンチウイルス、複数のスレッドの等価物は、異なるタスクを実行する場合、プロセスは、360ソフトウェアを実行するなど、複数のスレッドの実行中に生成することができるが、人のプロセスが実行され(のみ容易にします)さんはこの戦いを理解しましょう。
- マルチスレッド:複数のスレッドがCPUは、自身のオペレータの各CPUによれば、複数で同時に実行される、順次単核CPU、マルチコアCPUを実行する場合は複数のスレッドが交互に行われます。
1.2、同期および非同期
同期:一度起動メソッドの呼び出しが、その後の行動を継続するためには、メソッド呼び出しが戻った後まで待たなければなりません
非同期:メソッド呼び出しはすぐに戻りますメソッドの呼び出しは、呼び出し側がメソッドが戻るまで待っていない、すぐ背後に動作し続けることができる始めます。
メッセージキューの詳細については、古典的かつ一般的な非同期の実装は次のとおりです。ユーザデータが高いデータベースの同時圧力サージの場合には、直接データベースに書き込まれ、要求する応答速度が遅くなった原因になります使用しないときは、メッセージキュー、。メッセージキューを使用した後、ユーザは、直ちにメッセージキューを送信した後、要求されたデータを返し、その後、消費者プロセスのメッセージ・キューによって非同期メッセージ・キューからデータを取得するためにデータベースに書き込まれます。このように、メッセージ・キュー・データベース・サーバの処理速度(メッセージ・キューは、データベースよりも良好なスケーラビリティを有する)、効果の速度が大幅に改善するからです。
1.3、並行性と並列性
同時実行:同時マルチタスク処理能力をサポートしますが、マルチタスクは必ずしも同時に行われていません。
パラレル:表現は、複数のタスクを同時に実行することができます。
たとえば、あなたが同時に食事が突然、あなたは半分の食事は、電話に応答するために携帯電話を拾うあなたは同時である携帯電話を、答えた後、複数のタスクを同時に処理することができ、食事の残りを食べ続けるために箸を置く食べて電話をかけてきたが、唯一の同じ時刻に実行することができますサイドを食べながら、あなたが電話に応答することができる場合、または電話に答えるか、食べて、これは平行です。
1.4、高同時実行
高並行性の問題は、一般的に、インターネットの分散システムアーキテクチャ設計を考慮しなければならないで並列に要求の多くを扱うことができるシステムを指します。
一般的な指標は、次のとおり、応答時間、スループット、二流QPSあたりのクエリ、同時ユーザーの数を。
1.5、ブロックと非ブロック
- ブロックされた:あなたは、現在のスレッドをブロックする前に結果を得ることができません。
- ノンブロッキング:障害物の反対。
1.6、クリティカル領域
一般的に共有領域を表すために使用される複数のスレッドで同時に使用することができますが、クリティカルセクションが占有されると、1つのスレッドだけ、それを使用することができ、それぞれの時間は、他のスレッドが待機しなければなりません。
2.方法スレッドを作成します。
2.1、継承Threadクラス
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("MyThread");
}
//测试
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
System.out.println("end");
}
}
結果:
end
MyThread
2.2匿名内部クラス
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
super.run();
System.out.println("thread_01");
}
};
t.start();
System.out.println("end");
}
結果:
end
thread_01
2.3、Runnableを実装
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println("thread");
}
public static void main(String[] args) {
Thread t = new Thread(new MyThread());
t.start();
System.out.println("end");
}
}
結果:
end
thread
2.4スレッドプール
スレッドプールを使用する1つの方法は、最も推奨され、後で詳しく説明します
3、スレッドのライフサイクル
3.1、新(新)
スレッドが新しいキーワード、新しい状態のためのスレッドを使用して作成されたとき。
3.2、Runnableを(レディ)
start()メソッドを呼び出した後ではなく、システムが選択されている実行スレッドを待ったときに、CPUを割り当てるためのシステムを待って、CPUに割り当てられ、彼は準備状態から動作状態になり、これはCPUスケジューラと呼ばれています。
3.3、実行中の(ランニング)
runメソッド内のコードを実行します。
3.4遮断(ブロッキング)
CPUに割り当てることはできませんこの場合、同期コード・ブロックまたは修飾方法は、スレッドの競合、実行時間の均一な糸であり得る競合スレッドが実行可能からロック状態になっている間、ロック実行可能状態になりますブロックされた状態に。そして、契約は唯一の同期をブロックし、代わりにブロックの待機状態のスレッドをロックします
3.5、待つ(無制限待機)
また、このような状況は、CPUに割り当てることができない場合、3例は待ち状態実行可能状態にして通しますがあります。
- 通知されるまで、引数なしのObject.wait()メソッドを呼び出します()またはのnotifyAll()実行可能状態ウェイクを返します。
- 引数なしThread.join()メソッドを呼び出します。Bのスレッドの実行が待機状態のAcで、この時間にわたって実施されるまで、スレッド()メソッドのコールB.joinは、スレッドが待機します。
- LockSupport.park()メソッドを呼び出します。LockSupportが導入されたユーティリティクラスのJava6ので、Javaとの契約でロックが彼の認識に基づいている、そしてスレッドが実行可能状態であることができますLockSupport.unpark(スレッドスレッド)メソッドを呼び出します。
3.6、Time_Waiting(待機する時間を制限)
- Object.wait(長いタイムアウト)。
- Thread.join(長いミリ秒)。
- Thread.sleep(長いミリ秒)
- LockSupport.parkNanos(オブジェクトブロックされ、長い締め切り)
- LockSupport.parkUntil(ロング締め切り)
3.7、デッド(終了)
私たちの実行スレッド実行方法の終わりに、またはそれは、最終的な状態に半分にスローされる例外を行います。
強制的にスレッドを終了する方法3.7.1
Thread.stop()メソッドは、他のスレッドがロックを取得することはできません、あなたはこのスレッドロックを取得する場合、この時間は停止しているので、このロックではない、放棄された推奨されません。
/**
* 使用interrupt来停止线程
*/
public class MyThread06 extends Thread {
@Override
public void run() {
for(int i = 0 ; i < 100000 ; i ++){
if(this.isInterrupted()){
System.out.println("end");
return;
}
System.out.println(Thread.currentThread().getName()+" : i = " + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new MyThread06();
t.start();
Thread.sleep(100);
t.interrupt();
}
}
4、インスタンス変数、およびスレッドの安全性
线程类中的实例变量针对其他线程有共享和不共享之分
4.1、ノー共有変数
/**
* 不共享变量
*/
public class MyThread01 extends Thread {
private int count = 5;
public MyThread01(){}
/**
* 构造器,
* @param name
*/
public MyThread01(String name) {
this.setName(name);
}
@Override
public void run() {
while (count> 0 ){
count--;
System.out.println(this.currentThread().getName()+" : "+count);
}
}
public static void main(String[] args) {
Thread t1 = new MyThread01("A");
Thread t2 = new MyThread01("B");
Thread t3 = new MyThread01("C");
t1.start();
t2.start();
t3.start();
}
}
結果:
A : 4
C : 4
C : 3
C : 2
C : 1
C : 0
B : 4
A : 3
B : 3
A : 2
A : 1
A : 0
B : 2
B : 1
B : 0
結果によって知ることができ、各スレッドが別々のインスタンス変数の数を持って、彼らはお互いに影響を与えます。
4.2、共有変数
/**
* 共享变量
*/
public class MyThread02 extends Thread {
private int count = 5;
@Override
public void run() {
while (count> 0 ){
count--;
System.out.println(this.currentThread().getName()+" : "+count);
}
}
public static void main(String[] args) {
MyThread02 t = new MyThread02();
Thread t1 = new Thread(t,"A");
Thread t2 = new Thread(t,"B");
Thread t3 = new Thread(t,"C");
t1.start();
t2.start();
t3.start();
}
}
結果:
A : 3
A : 1
A : 0
B : 3
C : 2
count--のほとんどのJVMで3段階の操作であるので、我々は、我々が下落になりたい、これはエラーとなっていることがわかります。
- クエリーカウント値。
- カウント1を計算値;
- カウントする新しい値を割り当てます。
ときに複数のスレッドが共有変数で動作し、この問題はスレッドセーフになります。
ソリューション:
- synchronizedキーワードを使用してください。
- AtomicInteger原子クラスを使用します。
このように、揮発性のキーワードは、原子性を保証するものではありません、視認性と防止並べ替えを確保するためにのみ揮発するので、使用することはできません。
これらは、後で詳しく説明します。
5、いくつかの一般的な方法
5.1、簡単な方法
/**
* 简单方法
*/
public class MyThread03 extends Thread {
@Override
public void run() {
//获取当前线程对象的引用
System.out.println(this.currentThread());
//获取线程 名称
System.out.println(this.currentThread().getName());//A
this.currentThread().setName("B");
System.out.println(this.currentThread().getName());//B
//获取线程 Id标识符
System.out.println(this.currentThread().getId());//12
//获取线程的 优先级 默认为5 最低优先级1,最高优先级10
System.out.println(this.currentThread().getPriority());//5
try {
//休眠1秒
Thread.sleep(1000*1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断当前线程是否存活
System.out.println(this.currentThread().isAlive());//ture
}
public static void main(String[] args) {
Thread t = new Thread(new MyThread03(),"A");
t.start();
}
}
5.2、は、setdaemon(ブール)
5.2.1、定義
他のユーザのスレッドが実行された場合も、サービススレッドと呼ばれるデーモンスレッドは、さえも終了ミアン、JVMは、デーモンスレッドが実行を停止しますJVMの実行を停止し、その後、実行を停止します、ユーザスレッドに他の専門的なサービスをスレッドA。
5.2.2設定
setDaemon(ture)
デーモンスレッドを設定する前に、は、setdaemon(トゥーレ)が配置されるスタート
/**
* 守护线程
*/
public class MyThread04 extends Thread {
@Override
public void run() {
System.out.println(this.currentThread().isDaemon());
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThread04");
}
public static void main(String[] args) {
Thread t = new MyThread04();
//设置为守护线程,其他线程执行完毕,守护线程也会立马推出
t.setDaemon(true);
t.start();
System.out.println("main");
}
}
5.2.3アプリケーション
GCスレッド
5.3、参加します()
5.3.1、参加方法の使用
主な目的は、それが呼び出しスレッドで方法Bをスレッドに参加し、スレッド間でシリアルパラレルプログラミングすることができる同期させることである、それはBがスレッド実行スレッドが再開したときにのみ実行が完了したことを言いました
例:
/**
* join
*/
public class MyThread05 implements Runnable {
@Override
public void run() {
for(int i = 0 ; i < 50 ; i++){
System.out.println(Thread.currentThread().getName() +" : i = " + i);
}
}
public static void main(String[] args) throws InterruptedException {
MyThread05 t = new MyThread05();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t1.join();
/**
* 主线成执行到这个位置放弃执行资格,等到t1执行完毕后再执行
*/
t2.start();
for(int i = 0 ; i < 50 ; i++){
System.out.println(Thread.currentThread().getName() +" : i = " + i);
}
}
}
結果:後終了T1、T2と主が交互に行います
別の:参加プロセスは、パラメータを追加することができるスレッドA(100)b.joinような呼び出しを待つ何ミリ秒を示し、Bは、次いでABが交互に行う、100ミリ秒待機スレッドをスレッド表します。(0)参加する、(0)()に参加すると同じです参加し、無期限に待機することを示しています。
まず、開始()、その後、参加()
5.3.2実装の原則
出典:
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
呼び出し元Bのスレッドスレッドjoin()メソッドは、()メソッドは、スレッドをスレッド待つと等価であるスレッドが終了(または待機時間に達した)ときB、Bは、Bのスレッドが自動的にのnotifyAll()メソッドを呼び出します呼び出します。