[TIL]20211024


ジャワ


ねじ山


プロセス


オペレーティングシステムでは、実行中のアプリケーションを前処理と呼びます.
2つの手帳を実行すると、2つのアプリケーションが手帳上で実行されます.

ねじ山


これは、タスクを完了するために順次実行されるコードを線に接続する名前の由来です.1つのスレッドはコード実行ストリームであるため、1つのプロセス内に2つのスレッドがある場合、2つのコード実行ストリームが生成されることを意味します.
また、スレッド間でオブジェクトを共有することもできます.

マルチタスク処理


オペレーティングシステムは、2つ以上のタスクを同時に処理します.つまり、並列運転です.
しかし,マルチタスク処理はマルチプロセスを意味するものではない.1つのプロセス内で、複数のタスクをスレッドで同時に処理することもできます.
ビデオプレーヤーの場合、1つのプロセスにおいて、基本的には、ビデオ再生と音声再生の2つのスレッド、すなわちマルチスレッドと考えられる.
各プロセスには、オペレーティングシステムが割り当てたメモリがあるため、互いに独立しています.
ただし、スレッドの場合、1つのスレッドが共有によってプロセスに割り当てられた限られたメモリによって例外が発生した場合、プロセス自体が終了し、他のスレッドに影響を与える可能性があります.

threadクラス


このクラスはRunnableをメディアボックスとしています.Thread thread = new Thread(Runnable target);この場合、Runnableはインタフェースタイプなので、インプリメンテーションオブジェクトを作成して代入する必要があります.
インプリメンテーションクラスではrun()を再定義して、作業スレッドが実行するコードを作成する必要があります.
つまり、そうです.
class Task implements Runnable {
  public void run() {
    //스레드가 실행할 코드
  }
}

Runnable task = new Task();
Thread thread = new Thread(task);
簡略化するには
Thread thread = new Thread( new Runnable() {
  public void run() {
    //스레드가 실행할 코드
  }
} );
このような匿名オブジェクト生成方式も広く用いられている.
また、ワークスレッドは直ちに実行すべきではなく、thread.start();のようにstart()メソッドを実行すべきである.
import java.awt.*;
public class Main {
	  public static void main(String[] args) {
		 Thread thread = new Thread(new Runnable() {
			 @Override
			 public void run() {
				 Toolkit toolkit = Toolkit.getDefaultToolkit();
				 for(int i = 0 ; i<5; i++) {
					 toolkit.beep();
					 try {Thread.sleep(500);} catch(Exception e) {}
				 }
			 }
		 });
		 thread.start();
		 
		 for(int i = 0; i<5; i++) {
			 System.out.println("띵 ");
			 try {Thread.sleep(500);} catch(Exception e) {}
		 }
	  }
}
これは,スレッドを用いてbefと出力を各クラスで同時に動作させるコードである.
また、Runnableインタフェースを使用して作業内容を作成する必要はなく、Threadのサブクラスを使用して作業スレッドを定義することもできます.
public class WorkerThread extends Thread {
	@Override
    public void run() {
    	//스레드가 실행할 코드
    }
}
Thread thread = new WorkerThread();

// 상속 + 익명 객체이용
import java.awt.*;
public class Main {
	  public static void main(String[] args) {
		 Thread thread = new Thread() {
			 @Override
			 public void run() {
				 Toolkit toolkit = Toolkit.getDefaultToolkit();
				 for(int i = 0 ; i<5; i++) {
					 toolkit.beep();
					 try {Thread.sleep(500);} catch(Exception e) {}
				 }
			 }
		 };
		 thread.start();
		 
		 for(int i = 0; i<5; i++) {
			 System.out.println("띵 ");
			 try {Thread.sleep(500);} catch(Exception e) {}
		 }
	  }
}
このように

同期メソッド


複数のスレッドで同じオブジェクト(共有オブジェクト)を使用すると、予期せぬ事態が発生します.user 1スレッドがaというオブジェクトのaを1として指定し、2秒待っている間にuser 2スレッドがaというオブジェクトのaを2に置き換え、2秒待っていると、2秒後にuser 1またはuser 2全体がa値を2に設定し、最終的にはuser 1に必要な値を得ることができない.
マルチスレッドプログラムでは,1つのスレッドしか実行できないコード領域を臨界領域と呼び,同期法を用いてこの問題を解決する.
スレッドがオブジェクト内で同期メソッドを実行すると、すぐにオブジェクトがロックされ、他のスレッドが同期メソッドを実行しないようにします.
public synchronised void method() {
  //임계영역, 단 하나의 스레드만 실행
}
同期メソッドのメソッド全体が臨界領域であるため、メソッドが実行されるとオブジェクトはすぐにロックされ、メソッドが終了するとロックが解除されます.
複数の同期メソッドがある場合、スレッドのいずれかが実行されると、他のスレッドはそのメソッドを実行できず、他の同期メソッドも実行できません.
しかしながら、他のスレッドでは、従来の方法は実行可能である.
上記のAオブジェクトの例を適用すると、set Memory()メソッドがsynchronizedに設定されている場合、user 1スレッドは2秒後に1という値を出力し、user 2は前のスレッドの終了後2秒以内に2という値を出力します.

スレッドのステータス


start()メソッドが呼び出されると、スレッドは실행 대기 상태になります.その後、オペレーティングシステムは、실행 상태であるrun()メソッドをCPUに実行させるスレッドを選択する.この状態では、run()メソッドが終了する前にスレッドを待機運転状態に戻すことができます.
これにより、実行待ち状態と実行状態との間で交互に実行されると、各スレッドのrun()メソッドを少しずつ実行することができる.일시 정지状態に入ることがありますが、この状態はスレッドが実行できない状態です.この時点では直ちに運転状態にすることはできません.待機運転状態を通過する必要があります.
スレッドのステータスを스레드 상태 제어と呼びます.

スレッド状態制御方法

interrupt():InterruptedExceptionは、一時停止中のスレッドで発生し、例外処理コード(catch)から実行中または終了中の状態に移行できます.sleep:スレッドを所定の時間にわたって一時停止状態にする.指定された時間後、システムは自動的に待機状態に入ります.
sleepが停止状態にある所定時間前にinterrupt()メソッドを呼び出すとInterruptedExceptionが発生するため、例外処理も必要になります.

スレッドの安全なクローズ


スレッドはrun()メソッドが終了すると自動的に終了するので、ブートメソッドが正常に終了することが重要です.

1.stopフラグを使用する方法。

~~~
boolean stop= false;
public void run() {
while(!stop){
  // 반복할 코드 작성.
  }
}
このようにboolean型のstopフラグを使用して終了することができる.
これが実現された場合、以下のコードに示す.
public class StopFlagExample {
	public static void main(String[] args)  {
		PrintThread printThread = new PrintThread();
		printThread.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
		}
		
		printThread.setStop(true);
	}
}
-----------------------------------------------------------------

public class PrintThread extends Thread {
	private boolean stop;
	
	public void setStop(boolean stop) {
	  this.stop = stop;
	}
	
	public void run() {	
		while(!stop) {
			System.out.println("실행 중");
		}	
		System.out.println("실행 종료");
	}
}

2.割り込み()メソッドの使用方法


割り込み()メソッドは、スレッドが一時停止状態にある場合に割り込み終了の役割を果たします.
これによりrun()メソッドを正常に終了できます.
Class ThreadA
~~
ThreadB threadB = new ThreadB();
threadB.start();
~~~
threadB.interrupt();
------------------------------------------------------------
Class ThreadB
public void run() {
  try{
  while(true) {
    ~~~~
    Thread.sleep(1);
  }
  }catch(InterruptedException e) {
  }
  //스레드가 사용한 자원 정리.
}
ThreadaがThreadbの割り込み()メソッドを実行すると、Threadbがsleep()メソッドで一時停止状態になると、Threadbは割り込みExceptionが発生して異常処理(catch)ブロックに移動します.
最終的にThreadbはwhileゲートを出てrun()メソッドを正常に終了します.
注意すべき点もあります.スレッドが実行待ちまたは実行中の場合、割り込み()メソッドが実行されると、InterruptedExceptionはすぐには発生せず、スレッドが将来一時停止状態にある場合に発生します.したがって、スレッドが一時停止状態にない場合、()メソッド呼び出しを中断することは意味がありません.だから一時停止のためにsleep(1)を使用します.
このメソッドを使用しない場合は、boolean演算子のThreadを返します.割り込み()を使用することもできます.
while(true) {
  if(Thread.interrupted()) {
    break;
  }
}

デーモンプロセス


このスレッドは、プライマリ・スレッドの作業を支援する補助的な役割を果たします.
設定はthread.setDaemon(true);、実行はthread.start();を使用できますが、メインスレッドが終了すると自動的に終了します.