Javaマルチスレッドの基礎知識まとめ(コード付き)

不言
リリース: 2019-02-21 14:31:04
転載
2811 人が閲覧しました

この記事は Java マルチスレッドの基本的な知識をまとめたものです (コード付き)。必要な方は参考にしていただければ幸いです。

Java メイン スレッド名

開始するプログラムはプロセスとして理解でき、プロセスにはメイン スレッドが含まれ、スレッドはサブタスクとして理解できます。 Java 次のコードを通じてデフォルトのメイン スレッド名を取得できます。

System.out.println(Thread.currentThread().getName());
ログイン後にコピー

実行結果は main です。これはスレッドの名前であり、main メソッドではありません。main メソッドはこのスレッドを通じて実行されます。

スレッドを作成する 2 つの方法

1. Thread クラスを継承します

public class Thread1 extends Thread {
    @Override
    public void run() {
        System.out.println("qwe");
    }
}
ログイン後にコピー

2. Runnable インターフェイスを実装します

public class Thread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("asd");
    }
}
ログイン後にコピー
Thread を実装します。 Runnable インターフェイスは複数のスレッドで実行され、コードの実行順序は呼び出し順序とは関係ありません。また、start メソッドが複数回呼び出された場合、
## がスローされます。 #currentThread メソッド

現在のコードが使用されているスレッドを返します。

public class Thread1 extends Thread {

    public Thread1() {
        System.out.println("构造方法的打印:" + Thread.currentThread().getName());
    }

    @Override
    public void run() {
        System.out.println("run 方法的打印:" + Thread.currentThread().getName());
    }
}
ログイン後にコピー
Thread1 thread1 = new Thread1();
thread1.start();
ログイン後にコピー
isAlive メソッド

を呼び出して、現在のスレッドがアクティブかどうかを確認します。

public class Thread1 extends Thread {
    @Override
    public void run() {
        System.out.println("run 方法的打印 Thread.currentThread().isAlive() == " + Thread.currentThread().isAlive());
        System.out.println("run 方法的打印 this.isAlive() == " + this.isAlive());
        System.out.println("run 方法的打印 Thread.currentThread().isAlive() == this.isAlive() == " + (Thread.currentThread() == this ? "true" : "false"));
    }
}
ログイン後にコピー
Thread1 thread1 = new Thread1();

System.out.println("begin == " + thread1.isAlive());
thread1.start();
Thread.sleep(1000);
System.out.println("end == " + thread1.isAlive());
ログイン後にコピー
実行結果は以下の通りです

begin == false
run 方法的打印 Thread.currentThread().isAlive() == true
run 方法的打印 this.isAlive() == true
run 方法的打印 Thread.currentThread() == this == true
end == false
ログイン後にコピー
thread1は1秒後に実行されますので、Thread.currentThread()とthisは同じオブジェクトであることが分かります。現在の run メソッドを実行しているスレッド オブジェクトは自分自身 (this) です。

スレッド オブジェクトがパラメータとして構築されている場合、start() で Thread オブジェクトにメソッドを渡すと、実行結果が前と異なります。この違いの理由は、Thread.currentThread() と this の違いによるものです。

System.out.println("begin == " + thread1.isAlive());
//thread1.start();
// 如果将线程对象以构造参数的方式传递给 Thread 对象进行 start() 启动
Thread thread = new Thread(thread1);
thread.start();

Thread.sleep(1000);
System.out.println("end == " + thread1.isAlive());
ログイン後にコピー
実行結果

begin == false
run 方法的打印 Thread.currentThread().isAlive() == true
run 方法的打印 this.isAlive() == false
run 方法的打印 Thread.currentThread() == this == false
end == false
ログイン後にコピー
Thread.currentThread().isAlive() は、Thread が true であるためです。 .currentThread() はスレッド オブジェクトを返します。また、このオブジェクトを使用してスレッドを開始するため、スレッドはアクティブな状態になります。

this.isAlive() が false であるかどうかを理解しやすくなります。スレッド オブジェクトによって開始されたスレッドを介して run メソッドを実行します。したがって、これは 2 つが同じオブジェクトではないことも意味します。

sleep メソッド

thread" は、指定されたミリ秒数内でスリープします。「実行スレッド」は、

Thread.currentThread() 返されたスレッドのみです。

Thread.sleep(1000);
ログイン後にコピー
スレッドを停止します。

Stopスレッドとは、スレッドがタスクを完了する前に実行中の操作を停止すること、つまり、現在の操作を放棄することを意味します。

Java で実行中のスレッドを終了するには、次の 3 つの方法があります。

  1. 終了フラグを使用してスレッドを正常に終了します。つまり、run メソッドが完了するとスレッドが終了します。

  2. stop メソッドを使用して強制的に終了します。スレッドを終了しますが、この方法はお勧めできません。

  3. #スレッドを中断するには、interrupt メソッドを使用します。
  4. ##スレッドを停止できません
割り込みメソッドの呼び出しは、現在のスレッドに停止のマークを付けるだけで、実際にはスレッドを停止しません。

public class Thread1 extends Thread {
    @Override
    public void run() {

        for(int i = 0; i < 500000; i++) {
            System.out.println(i);
        }
    }
}
ログイン後にコピー
Thread1 thread1 = new Thread1();
thread1.start();
Thread.sleep(2000);
thread1.interrupt();
ログイン後にコピー

出力された結果によると、2 秒後に割り込みメソッドを呼び出します。スレッドは停止しないが、このループを 500000 回実行すると、run メソッドが終了し、スレッドが停止します。

#スレッドが停止しているかどうかを判断します。 # #スレッドを停止としてマークした後、スレッド内でスレッドが停止としてマークされているかどうかを判断し、停止としてマークされている場合はスレッドを停止する必要があります。

#2 つの判断方法:

#Thread.interrupted(); this.interrupted();

this.isInterrupted();

    ## を使用することもできます。 #以下はメソッドの 2 つのソース コードです:
  1.     public static boolean interrupted() {
            return currentThread().isInterrupted(true);
        }
        
        public boolean isInterrupted() {
            return isInterrupted(false);
        }
    ログイン後にコピー

    interrupted()
  2. メソッド データの静的メソッド。つまり、現在のスレッドが中断されたかどうかを判断します。
  3. スレッドが中断されているかどうかを判断します。

  4. interrupted()
公式 Web サイトからのメソッドのポイント。

スレッドの中断ステータスは、このメソッドによってクリアされます。つまり、このメソッドが連続して 2 回呼び出された場合、2 回目は false を返します (最初の呼び出しで割り込みステータスがクリアされた後、2 番目の呼び出しで割り込みステータスが確認される前に現在のスレッドが再度割り込まれた場合を除きます)。 .

Exception stop thread<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">public class Thread1 extends Thread {     @Override     public void run() {         try {             for (int i = 0; i &lt; 500000; i++) {                 if (this.isInterrupted()) {                     System.out.println(&quot;线程停止&quot;);                     throw new InterruptedException();                 }                 System.out.println(&quot;i = &quot; + i);             }         } catch (InterruptedException e) {             System.out.println(&quot;线程通过 catch 停止&quot;);             e.printStackTrace();         }     } }</pre><div class="contentsignin">ログイン後にコピー</div></div> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">Thread1 thread1 = new Thread1(); thread1.start(); Thread.sleep(1000); thread1.interrupt();</pre><div class="contentsignin">ログイン後にコピー</div></div> 出力結果、これらは最後の数行です:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">i = 195173 i = 195174 i = 195175 线程停止 线程通过 catch 停止 java.lang.InterruptedException     at Thread1.run(Thread1.java:9)</pre><div class="contentsignin">ログイン後にコピー</div></div>もちろん、

throw new InterruptedException();# を置き換えることもできます。 ## と
return はすべて同じです。スレッドを終了します。
スリープ状態で停止

スレッドが

Thread.sleep()

を呼び出した場合メソッドを呼び出してスレッドをスリープ状態にすると、

thread1.interrupt ()
が呼び出され、その後 InterruptedException Exception.<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">java.lang.InterruptedException: sleep interrupted     at java.lang.Thread.sleep(Native Method)     at Thread1.run(Thread1.java:8)</pre><div class="contentsignin">ログイン後にコピー</div></div>スレッドが強制的に停止されます

スレッドを強制的に停止するには、

stop

メソッドを使用できますが、このメソッドは廃止されており、次の理由からお勧めできません。<ol class=" list-paddingleft-2"> <li><p>即刻抛出 ThreadDeath 异常, 在线程的run()方法内, 任何一点都有可能抛出ThreadDeath Error, 包括在 catch 或 finally 语句中. 也就是说代码不确定执行到哪一步就会抛出异常.</p></li> <li><p>释放该线程所持有的所有的锁. 这可能会导致数据不一致性.</p></li> </ol> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">public class Thread1 extends Thread {     private String userName = &quot;a&quot;;     private String pwd = &quot;aa&quot;;     public String getUserName() {         return userName;     }     public void setUserName(String userName) {         this.userName = userName;     }     public String getPwd() {         return pwd;     }     public void setPwd(String pwd) {         this.pwd = pwd;     }     @Override     public void run() {         this.userName = &quot;b&quot;;         try {             Thread.sleep(100000);         } catch (InterruptedException e) {             e.printStackTrace();         }         this.pwd = &quot;bb&quot;;     } }</pre><div class="contentsignin">ログイン後にコピー</div></div> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">Thread1 thread1 = new Thread1(); thread1.start(); Thread.sleep(1000); thread1.stop(); System.out.println(thread1.getUserName() + &quot;     &quot; + thread1.getPwd());</pre><div class="contentsignin">ログイン後にコピー</div></div> <p>输出结果为:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">b     aa</pre><div class="contentsignin">ログイン後にコピー</div></div> <p>我们在代码中然线程休眠 Thread.sleep(100000); 是为了模拟一些其它业务逻辑处理所用的时间, 在线程处理其它业务的时候, 我们调用 stop 方法来停止线程.</p> <p>线程是被停止了也执行了 System.out.println(thread1.getUserName() + "     " + thread1.getPwd()); 来帮我们输出结果, 但是 this.pwd = "bb"; 并没有被执行.</p> <p>所以, 当调用了 stop 方法后, 线程无论执行到哪段代码, 线程就会立即退出, 并且会抛出 ThreadDeath 异常, 而且会释放所有锁, 从而导致数据不一致的情况.</p> <p>interrupt 相比 stop 方法更可控, 而且可以保持数据一致, 当你的代码逻辑执行完一次, 下一次执行的时候, 才会去判断并退出线程.</p> <p>如果大家不怎么理解推荐查看 为什么不能使用Thread.stop()方法? 这篇文章. 下面是另一个比较好的例子.</p> <p>如果线程当前正持有锁(此线程可以执行代码), stop之后则会释放该锁. 由于此错误可能出现在很多地方, 那么这就让编程人员防不胜防, 极易造成对象状态的不一致. 例如, 对象 obj 中存放着一个范围值: 最小值low, 最大值high, 且low不得大于high, 这种关系由锁lock保护, 以避免并发时产生竞态条件而导致该关系失效.</p> <p>假设当前low值是5, high值是10, 当线程t获取lock后, 将low值更新为了15, 此时被stop了, 真是糟糕, 如果没有捕获住stop导致的Error, low的值就为15, high还是10, 这导致它们之间的小于关系得不到保证, 也就是对象状态被破坏了!</p> <p>如果在给low赋值的时候catch住stop导致的Error则可能使后面high变量的赋值继续, 但是谁也不知道Error会在哪条语句抛出, 如果对象状态之间的关系更复杂呢?这种方式几乎是无法维护的, 太复杂了!如果是中断操作, 它决计不会在执行low赋值的时候抛出错误, 这样程序对于对象状态一致性就是可控的.</p> <h2>suspend 与 resume 方法</h2> <p>用来暂停和恢复线程.</p> <h3>独占</h3> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">public class PrintObject {     synchronized public void printString(){         System.out.println(&quot;begin&quot;);         if(Thread.currentThread().getName().equals(&quot;a&quot;)){             System.out.println(&quot;线程 a 被中断&quot;);             Thread.currentThread().suspend();         }         if(Thread.currentThread().getName().equals(&quot;b&quot;)){             System.out.println(&quot;线程 b 运行&quot;);         }         System.out.println(&quot;end&quot;);     } }</pre><div class="contentsignin">ログイン後にコピー</div></div> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">try{     PrintObject  pb = new PrintObject();     Thread thread1 = new Thread(pb::printString);     thread1.setName(&quot;a&quot;);     thread1.start();     thread1.sleep(1000);     Thread thread2 = new Thread(pb::printString);     thread2.setName(&quot;b&quot;);     thread2.start(); }catch(InterruptedException e){ }</pre><div class="contentsignin">ログイン後にコピー</div></div> <p>输出结果:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">begin 线程 a 被中断</pre><div class="contentsignin">ログイン後にコピー</div></div> <p>当调用 Thread.currentThread().suspend(); 方法来暂停线程时, 锁并不会被释放, 所以造成了同步对象的独占.</p> <p class="comments-box-content"><br></p>

以上がJavaマルチスレッドの基礎知識まとめ(コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート