class ThreadA extends Thread {
public void run() {
// 수행할 문장들 기술
}
}
ThradA TA = new ThreadA();
TA.start();
public class ThreadTest extends Thread
{
public void run()
{
// 인터럽트 됬을때 예외처리
try
{
for(int i = 0 ; i < 10 ; i++)
{
// 스레드 0.5초동안 대기
Thread.sleep(500);
System.out.println("Thread : " + i);
}
}catch(InterruptedException e)
{
System.out.println(e);
}
}
}
public class Thread1
{
public static void main(String args[])
{
ThreadTest t1 = new ThreadTest();
ThreadTest t2 = new ThreadTest();
// 1. 동시에 똑같은 숫자가 나오고(start)
/*t1.start();
t2.start();*/
// 2. 번갈아가면서 나옴(run)
t1.run();
t2.run();
}
}
동시에 똑같은 숫자가 나옴
번갈아가면서 나옴
package study;
//단일스레드
public class S_thread {
public void display() {
for(char i = 'A'; i <= 'Z'; i++) {
System.out.print(i);
}
System.out.println();
}
public static void main(String[] args) {
System.out.println("Main 스레드 시작 !!!");
new S_thread().display();
for(char i = 'a'; i <= 'z'; i++) {
System.out.print(i);
}
System.out.println();
System.out.println("Main 스레드 끝!!!");
}
}
package study;
public class M_thread extends Thread {
@Override
public void run() {
for(char i = 'A'; i<= 'Z'; i++) {
System.out.print(i);
try {
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
}
}
package study;
public class M2_thread implements Runnable{
@Override
public void run() {
for(char i = 'a'; i <= 'z'; i++) {
System.out.print(i);
try {
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
package study;
public class MultiThread {
public static void main(String[] args) throws InterruptedException {
//M_thread m = new M_thread();
//m.start();
new M_thread().start();
//M2_thread m2 = new M2_thread();
//Thread thread = new Thread(m2);
//thread.start();
new Thread(new M2_thread()).start();
for(int i = 0; i<= 9; i++) {
System.out.print(i);
Thread.sleep(500); // 0.5초동안 스레드의 흐름을 일시정지
}
}
}
package study;
public class ThreadSynchronizedTest {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.setName("t1-Thread");
t2.setName("t2-Thread");
t1.start();
t2.start();
}
}
class Account {
int balance = 1000;
public synchronized void withDraw(int money) {
if(balance >= money) {
try {
Thread thread = Thread.currentThread(); //현재 쓰레드
System.out.println(thread.getName() + " 출금 금액 ->> " + money);
Thread.sleep(1000);
balance -= money; //balance = balance - money
System.out.println(thread.getName()+ " balance : " + balance);
}catch(Exception e) {
}
}
}
}
class Task implements Runnable {
Account acc = new Account();
@Override
public void run() {
while(acc.balance > 0) {
// 100, 200, 300 중의 한 값을 임의로 선택해서 출금(withDraw)한다.
int money = (int)(Math.random() * 3 + 1)* 100;
acc.withDraw(money);
}
}
}
위 예제에 대해 설명을 하면, Account라는 클래스에는 balance 잔액과 이 잔액을 삭감(withDraw)시키는 인출메서드가 있습니다. 스레드를 만들 때 Runnable 인터페이스를 구현하여 Task 클래스를 만들고 이 Task 클래스를 Thread 객체 생성시 생성자에 매개변수로 넣으면 만든 스레드가 Task에 정의되어 있는대로 일을 실행합니다.
Runnable을 구현하여 만든 Task에 100, 200, 300 중 랜덤하게 값을 전달받아 money 변수에 할당하고 그 금액만큼 Account 인스턴스의 인출메서드를 호출해 balance (잔액)을 출금시키는 일을 구현해놨습니다. 다음 main 메서드에서 스레드 t1, t2를 만들고 각각의 스레드 이름을 정의합니다. t1, t2 스레드가 시작하면 잔액이 0이 될 때까지 두 스레드가 경쟁하며 출금시킬 것입니다.
여기서 멀티스레드의 문제점이 발견됩니다. balance thread-safe가 되지 않았기 때문에 t1 스레드가 잔액을 삭감하기 전에 t2가 balance에 접근해 삭감을 해버리고 다시 t1이 sleep()에서 깨어나 balance을 삭감해버리기 때문에
잔액이 0 이하의 마이너스 값을 가지게 됩니다.
해결하는 방법은 ->synchronized
키워드를 리턴타입 앞에 붙여주면 됩니다. t1 스레드가 먼저 공유데이터나 메서드에 점유하고 있는 상태인 경우 block으로 처리하기 때문에 t1 이외의 스레드의 접근을 막습니다. t1 스레드가 작업을 다 끝내면 .unblock으로 처리하여 t1 이외의 스레드의 접근을 허락합니다.
한 가지가 바뀐 것을 볼 수 있다.
package study;
public class ThreadSynchronizedTest {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.setName("t1-Thread");
t2.setName("t2-Thread");
t1.start();
t2.start();
}
}
class Account {
int balance = 1000;
public synchronized void withDraw(int money) {
if(balance >= money) {
try {
Thread thread = Thread.currentThread(); //현재 쓰레드
System.out.println(thread.getName() + " 출금 금액 ->> " + money);
Thread.sleep(1000);
balance -= money; //balance = balance - money
System.out.println(thread.getName()+ " balance : " + balance);
}catch(Exception e) {
}
}
}
}
class Task implements Runnable {
Account acc = new Account();
@Override
public void run() {
while(acc.balance > 0) {
// 100, 200, 300 중의 한 값을 임의로 선택해서 출금(withDraw)한다.
int money = (int)(Math.random() * 3 + 1)* 100;
acc.withDraw(money);
}
}
}
synchronized 키워드를 사용함으로써 balance 공유데이터에 대한 thread-safe를 시켰기 때문에
데이터나 메서드 점유하고 있는 스레드가 온전히 자신의 작업을 마칠 수 있습니다.
참고: https://coding-start.tistory.com/68 [코딩스타트]
와우... 감사합니다.