1. スレッドを作成する
Java でスレッドを作成するには、Thread クラスを使用する方法と Runnable インターフェイスを使用する方法の 2 つがあります。 Runnable インターフェイスを使用する場合は、Thread インスタンスを作成する必要があります。したがって、Thread クラスまたは Runnable インターフェイスを通じてスレッドを作成する場合は、Thread クラスまたはそのサブクラスのインスタンスを作成する必要があります。スレッドコンストラクター:
- パブリックスレッド();
- public Thread(実行可能なターゲット);
- public Thread(文字列名);
- public Thread(実行可能なターゲット、文字列名);
- public Thread(ThreadGroup グループ、実行可能なターゲット);
- public Thread(ThreadGroup グループ、文字列名);
- public Thread(ThreadGroup グループ、実行可能なターゲット、文字列名);
- public Thread(ThreadGroup グループ、実行可能なターゲット、文字列名、長いスタックサイズ);
方法 1: Thread クラスを継承し、run メソッドをオーバーライドする
次のようにコードをコピーします。
パブリック クラス ThreadDemo1 {
public static void main(String[] args){
デモ d = 新しいデモ();
d.start();
for(int i=0;i<60;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class Demo extends Thread{
public void run(){
for(int i=0;i<60;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
方法 2:
次のようにコードをコピーします。
パブリック クラス ThreadDemo2 {
public static void main(String[] args){
デモ2 d =新しいデモ2();
スレッド t = 新しいスレッド(d);
t.start();
for(int x=0;x<60;x++){
System.out.println(Thread.currentThread().getName()+x);
}
}
}
クラス Demo2 は Runnable{ を実装します
public void run(){
for(int x=0;x<60;x++){
System.out.println(Thread.currentThread().getName()+x);
}
}
}
2. スレッドのライフサイクル人間が生まれ、老い、病気になり、死ぬのと同じように、スレッドも開始 (待機)、実行、ハング、停止という 4 つの異なる状態を経る必要があります。これら 4 つの状態は、Thread クラスのメソッドを通じて制御できます。 Thread クラスのこれら 4 つの状態に関連するメソッドを以下に示します。
- // スレッドを開始します
- publicvoid start();
- publicvoid run();
- // スレッドを一時停止してウェイクアップします
- publicvoidresume(); // 使用は推奨されません。
- publicvoid stop( ); // 使用は推奨されません。
- publicstaticvoid sleep(長いミリ秒);
- publicstaticvoid sleep(long millis, int nanos);
- // スレッドを終了する
- publicvoid stop( ); // 使用は推奨されません。
- publicvoid 割り込み( );
- // スレッドのステータスを取得する
- publicboolean isAlive( );
- publicboolean isInterrupted( );
- publicstaticboolean 中断されました( );
- // 結合メソッド
- publicvoid join( ) は InterruptedException をスローします。
スレッドは確立直後に run メソッド内のコードを実行せず、待機状態になります。スレッドが待機状態にある場合、Thread クラスのメソッドを通じて、スレッドの優先順位 (setPriority)、スレッド名 (setName)、スレッド タイプ (setDaemon) などのスレッドのさまざまな属性を設定できます。
start メソッドが呼び出されると、スレッドは run メソッド内のコードの実行を開始します。スレッドは実行状態になります。 Thread クラスの isAlive メソッドを使用して、スレッドが実行されているかどうかを確認できます。スレッドが実行状態にある場合、isAlive は true を返します。isAlive が false を返す場合、スレッドは待機状態または停止状態にある可能性があります。次のコードは、スレッドの作成、実行、停止の 3 つの状態間の切り替えを示し、対応する isAlive 戻り値を出力します。
スレッドが run メソッドの実行を開始すると、run メソッドが完了するまでスレッドは終了しません。ただし、スレッドの実行中に、スレッドの実行を一時的に停止するために使用できる方法が 2 つあります。これら 2 つの方法はサスペンドとスリープです。サスペンドを使用してスレッドを一時停止した後、再開メソッドを使用してスレッドをウェイクアップできます。 sleep を使用してスレッドをスリープ状態にした後、スレッドは設定された時間が経過した後にのみ準備完了状態になることができます (スレッドのスリープ終了後、スレッドはすぐには実行されない場合がありますが、システムがスケジュールするのを待って準備完了状態になるだけです)。 。
sleep メソッドを使用する際の注意点は次の 2 つです。
1. sleep メソッドには 2 つのオーバーロード形式があります。オーバーロード形式の 1 つは、ミリ秒だけでなくナノ秒も設定できます (1,000,000 ナノ秒は 1 ミリ秒に相当します)。ただし、ほとんどのオペレーティング システム プラットフォームの Java 仮想マシンはナノ秒まで正確ではないため、スリープにナノ秒が設定されている場合、Java 仮想マシンはこの値に最も近いミリ秒を取得します。
2. sleep メソッドを使用する場合は、throws または try{...}catch{...} を使用する必要があります。 run メソッドでは throw を使用できないため、try{...}catch{...} のみを使用できます。スレッドがスリープ状態で、割り込みメソッドを使用してスレッドを中断すると、スリープは InterruptedException をスローします。スリープ メソッドは次のように定義されます。
- public static void sleep( long millis) は InterruptedExceptionをスローします
- public static void sleep( long millis, int nanos) は InterruptedExceptionをスローします
スレッドを終了するには 3 つの方法があります。
1. 終了フラグを使用して、スレッドを正常に終了します。つまり、run メソッドが完了するとスレッドが終了します。
2. stop メソッドを使用してスレッドを強制的に終了します (サスペンドや再開と同様に停止によっても予期しない結果が生じる可能性があるため、この方法は推奨されません)。
3. スレッドを中断するには、interrupt メソッドを使用します。
1. 終了フラグを使用してスレッドを終了します。
run メソッドが実行されると、スレッドは終了します。ただし、run メソッドが終了しない場合があります。たとえば、スレッドはサーバー プログラムでクライアントの要求や、周期的な処理を必要とするその他のタスクを監視するために使用されます。この場合、これらのタスクは通常、while ループなどのループ内に配置されます。ループを永久に実行したい場合は、while(true){...} を使用して処理できます。ただし、特定の条件で while ループを終了させたい場合、最も直接的な方法は、ブール型フラグを設定し、このフラグを true または false に設定して while ループを終了するかどうかを制御することです。終了フラグを使用してスレッドを終了する例を以下に示します。
join メソッドの機能は、非同期実行スレッドを同期実行にすることです。つまり、スレッド インスタンスの start メソッドが呼び出されると、このメソッドはすぐに戻ります。start メソッドの呼び出し後にこのスレッドによって計算された値を使用する必要がある場合は、join メソッドを使用する必要があります。 join メソッドを使用しない場合、start メソッドに続くステートメントの実行時にスレッドが実行されるという保証はありません。 join メソッドを使用した後は、このスレッドが終了するまでプログラムは実行を続行しません。次のコードは、結合の使用法を示しています。
3.マルチスレッドのセキュリティ問題
問題の原因: 複数のステートメントが同じスレッド上で動作し、データを共有する場合、1 つのスレッドが複数のステートメントの一部のみを実行し、実行が完了する前に別のスレッドが実行に参加するため、共有データ エラーが発生します。
解決策: 共有データを操作する複数のステートメントの場合、実行プロセス中に実行できるスレッドは 1 つだけです。他のスレッドは実行されません。
同期コードブロック:
次のようにコードをコピーします。
パブリック クラス ThreadDemo3 {
public static void main(String[] args){
チケット t =新しいチケット();
スレッド t1 = 新しいスレッド(t,"ウィンドウ 1");
スレッド t2 = 新しいスレッド(t,"ウィンドウ 2");
スレッド t3 = 新しいスレッド(t,"ウィンドウ 3");
スレッド t4 = 新しいスレッド(t,"ウィンドウ 4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
クラスチケットは Runnable{ を実装します
プライベート int チケット =400;
public void run(){
while(true){
同期化 (new Object()) {
試す {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
if(チケット<=0)
壊す;
System.out.println(Thread.currentThread().getName()+"---販売"+ticket--);
}
}
}
}
同期機能
次のようにコードをコピーします。
パブリック クラス ThreadDemo3 {
public static void main(String[] args){
チケット t =新しいチケット();
スレッド t1 = 新しいスレッド(t,"ウィンドウ 1");
スレッド t2 = 新しいスレッド(t,"ウィンドウ 2");
スレッド t3 = 新しいスレッド(t,"ウィンドウ 3");
スレッド t4 = 新しいスレッド(t,"ウィンドウ 4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
クラスチケットは Runnable{ を実装します
プライベート int チケット = 4000;
public synchronized void saleTicket(){
if(チケット>0)
System.out.println(Thread.currentThread().getName()+"販売済み"+ticket--);
}
public void run(){
while(true){
saleTicket();
}
}
}
同期関数ロックは this、静的同期関数ロックは class
スレッド間の通信
次のようにコードをコピーします。
パブリック クラス ThreadDemo3 {
public static void main(String[] args){
クラス人{
パブリック文字列名。
プライベート文字列の性別。
public void set(文字列名,文字列性別){
this.name =名前;
this.gender =性別;
}
パブリック void get(){
System.out.println(this.name+"...."+this.gender);
}
}
最終人物 p =新しい人物();
new Thread(new Runnable(){
public void run(){
int x=0;
while(true){
if(x==0){
p.set("張三", "男性");
}それ以外{
p.set("リリ", "nv");
}
x=(x+1)%2;
}
}
})。始める();
new Thread(new Runnable(){
public void run(){
while(true){
p.get();
}
}
})。始める();
}
}
/*
張三....男 張三....男
リリ....nv
リリ....男性 張三....nv
リリ……男性
*/
上記のコードを変更します
次のようにコードをコピーします。
パブリック クラス ThreadDemo3 {
public static void main(String[] args){
クラス人{
パブリック文字列名。
プライベート文字列の性別。
public void set(文字列名,文字列性別){
this.name =名前;
this.gender =性別;
}
パブリック void get(){
System.out.println(this.name+"...."+this.gender);
}
}
最終人物 p =新しい人物();
new Thread(new Runnable(){
public void run(){
int x=0;
while(true){
同期 (p) {
if(x==0){
p.set("張三", "男性");
}それ以外{
p.set("リリ", "nv");
}
x=(x+1)%2;
}
}
}
})。始める();
new Thread(new Runnable(){
public void run(){
while(true){
同期 (p) {
p.get();
}
}
}
})。始める();
}
}
/*
リリ....nv
リリ....nv
リリ....nv
リリ....nv
リリ....nv
リリ....nv
チャン・サン....男 チャン・サン....男 チャン・サン....男 チャン・サン....男
*/
ウェイクアップメカニズムを待機中
次のようにコードをコピーします。
/*
*スレッド待機ウェイクアップメカニズム
※待機時と起床時は同じロックである必要があります
*/
パブリック クラス ThreadDemo3 {
プライベート静的ブール フラグ =false;
public static void main(String[] args){
クラス人{
パブリック文字列名。
プライベート文字列の性別。
public void set(文字列名,文字列性別){
this.name =名前;
this.gender =性別;
}
パブリック void get(){
System.out.println(this.name+"...."+this.gender);
}
}
最終人物 p =新しい人物();
new Thread(new Runnable(){
public void run(){
int x=0;
while(true){
同期 (p) {
if(フラグ)
試す {
p.wait();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
};
if(x==0){
p.set("張三", "男性");
}それ以外{
p.set("リリ", "nv");
}
x=(x+1)%2;
フラグ = true;
p.notifyAll();
}
}
}
})。始める();
new Thread(new Runnable(){
public void run(){
while(true){
同期 (p) {
if(!フラグ)
試す {
p.wait();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
};
p.get();
フラグ = false;
p.notifyAll();
}
}
}
})。始める();
}
}
生産と消費の仕組み1
次のようにコードをコピーします。
パブリック クラス ThreadDemo4 {
プライベート静的ブール フラグ =false;
public static void main(String[] args){
クラスグッズ{
プライベート文字列名。
プライベート整数番号;
public synchronized void generated(文字列名){
if(フラグ)
試す {
待って();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
this.name =name+"Number:"+num++;
System.out.println("Produced...."+this.name);
フラグ = true;
すべて通知();
}
public synchronized void Consumer(){
if(!フラグ)
試す {
待って();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
System.out.println("****** の消費"+name);
フラグ = false;
すべて通知();
}
}
最終商品 g =新しい商品();
new Thread(new Runnable(){
public void run(){
while(true){
g.Produce("商品");
}
}
})。始める();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
}
}
})。始める();
}
}
生産と消費の仕組み2
次のようにコードをコピーします。
パブリック クラス ThreadDemo4 {
プライベート静的ブール フラグ =false;
public static void main(String[] args){
クラスグッズ{
プライベート文字列名。
プライベート整数番号;
public synchronized void generated(文字列名){
while(フラグ)
試す {
待って();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
this.name =name+"Number:"+num++;
System.out.println(Thread.currentThread().getName()+"Produced...."+this.name);
フラグ = true;
すべて通知();
}
public synchronized void Consumer(){
while(!フラグ)
試す {
待って();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"****** の消費"+name);
フラグ = false;
すべて通知();
}
}
最終商品 g =新しい商品();
new Thread(new Runnable(){
public void run(){
while(true){
g.Produce("商品");
}
}
},"プロデューサーNo.1").start();
new Thread(new Runnable(){
public void run(){
while(true){
g.Produce("商品");
}
}
},"プロデューサーNo.2").start();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
}
}
},"消費者No.1").start();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
}
}
},"消費者その2").start();
}
}
/*
消費者No.2消費****** 製品番号:48049
プロデューサーワンプロデュース....商品番号:48050
消費者No.1 消費者****** 製品番号:48050
プロデューサーワンプロデュース....商品番号:48051
消費者No.2消費****** 製品番号:48051
プロデューサーNo.2プロデュース....商品番号:48052
消費者No.2消費****** 製品番号:48052
プロデューサーワンプロデュース....商品番号:48053
消費者No.1 消費者****** 商品番号:48053
プロデューサーワンプロデュース....商品番号:48054
消費者No.2消費****** 製品番号:48054
プロデューサーNo.2プロデュース....商品番号:48055
消費者No.2消費****** 製品番号:48055
*/