여러 스레드를 가진다
= 병렬적으로 작업을 할 수 있다는 것
= 한 번에 여러 작업 가능
=> 멀티 태스킹
run() 메서드에다가 스레드가 실행할 코드를 작성해야 한다.run() 메서드는 Runnable 인터페이스와 Thread 클래스에 정의되어져 있다.// Runnable 인터페이스가 run 메서드를 강제
public interface Runnable {
public abstract void run();
}
// Thread 클래스는 Runnable 인터페이스를 구현함
class Thread implements Runnable{
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new ThreadTask1());
}
}
class ThreadTask1 implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.print("#");
}
}
}
public class Main {
public static void main(String[]args) {
// Thread 클래스를 상속받은 클래스를 인스턴스화하여 스레드를 생성
ThreadTask2 thread2 = new ThreadTask2();
}
}
class ThreadTask2 extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.print("#");
}
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new ThreadTask1());
thread.start();
}
}
start() 메소드를 통해서, 스레드를 실행 대기 상태로 바꿔준다.
실제로 스레드를 실행시켜 주는 것은 운영체제의 스케쥴러이다.

출처: https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=qbxlvnf11&logNo=220921178603
스레드가 동일한 데이터를 공유하게 되면서 문제가 발생한다.
한 스레드가 코드를 실행할 때, 다른 스레드가 그 과정에 끼어들어 작업을 하게 되면 이것저것이 꼬이기 때문이다.
이런 문제가 발생하지 않도록 하는 것이 스레드 동기화이고, 이때 임계 영역과 락을 사용한다.
스레드 A는 임계 영역을 포함한 객체에 대한 락을 얻어, 임계 영역 내의 코드를 실행한다.
이때 스레드 A를 제외한 다른 스레드는 락이 없기 때문에, 해당 임계 영역에 접근할 수 없다.
스레드 A가 락을 반납하면, 다른 스레드 중 하나가 락을 획득하여 임계 영역 내의 코드를 실행하게 된다.
synchronized 키워드를 통해, 임계 영역을 설정한다.