영어단어장 프로그램을 작성해보자.
1. 지난 단어장을 수정하여 save라는 명령을 입력하면 wordbook.txt에 단어를 저장
2. 프로그램을 재시작할 때 wordbook.txt에서 단어를 읽어와 메모리에 저장
1.스레드(Thread)
프로세스
- 윈도우 작업 관리자에서 프로세스 탭에 올라와 있는 어플리케이션 하나
- 운영체제로부터 필요한 메모리를 할당받아 어플리케이션의 코드를 실행
멀티 태스킹
- 두가지 이상의 작업을 동시(병렬작업)에 처리하는 것
쓰레드
- 하나의 프로세스 내부에서 독립적으로 실행되는 작업단위
- 운영체제에 의해 관리되는 하나의 작업 혹은 Task를 의미
- 다중 쓰레드 작업시에는 각 쓰레드끼리 정보를 주고 받을 수 있어 처리 과정의 오류를 줄일 수 있음
- 각 프로세스끼리는 정보를 주고 받을 수 없음
- JVM에 의해 하나의 프로세스가 발생, main() 안에 실행문들이 하나의 쓰레드
멀티 쓰레드
- 여러 쓰레드를 동시에 실행시키는 응용프로그램을 작성하는 기법
- 메모리 공유로 인한 시스템 자원 소모가 줄어듬
- 동시에 두가지 이상의 활용이 가능
- 서로 자원을 소모하다가 충돌이 일어날 가능성이 있음
- 코드가 난해해질 가능성이 있음
쓰레드 생성 방법1 (Thread 클래스 상속)
public class 클래스명 extends Thread {
public void run(){
쓰레드 객체가 start() 호출하면 실행될 문장; //start호출하면 run자동 실행
...
}
}
Thread 참조변수 = new 클래스명();
참조변수.start(); => run메소드가 호출된다
✔ Thread 클래스는 start() 실행시 run() 메소드가 수행되도록 내부적으로 처리
쓰레드 생성방법 2 (Runnable 인터페이스를 구현)
public class 클래스명 implements Ruannable {
public void run(){
쓰레드 객체가 start() 호출하면 실행될 문장;
...
}
}
Runnable 참조변수 = new 클래스명();
Thread 참조변수2 = new Thread(참조변수1);
참조변수2.start();
동기화(Synchronized)
- 멀티 스레드 프로세스에서는 다른 쓰레드의 작업에 영향을 미칠 수 있기 때문에 진행중인 작업이 다른
쓰레드에 간섭을 받지 않게 동기화가 필요
메소드
public synchronized 반환형 메소드명(매개변수1, 매개변수2 ...){
...
}
문장
synchronized(this){
...
}
join()
- 쓰레드는 메인쓰레드가 종료되어도 다른 쓰레드는 백그라운드에서 동작하며 종료되지 않음
- join을 이용하면 다른 쓰레드가 종료될 때까지 메인쓰레드가 기다림
스레드 우선순위
- 스레드가 여러개인 경우 우선순위가 높은 쓰레드가 제어권을 많이 가지게 됨
- 우선순위는 1 ~ 10까지 int값으로 할당
- 기본 우선순위는 5
- 우선순위가 높은 쓰레드는 실행기회가 많이 주어짐
MAX_PRIORITY : 가장 높은 순위, 10
NORM_PRIORITY : 일반적인 순위, 5
MIN_PRIORITY : 가장 낮은 순위, 1
yield()
- 다른 스레드에 자원사용을 양보할 때 사용
- 우선순위가 낮은 스레드에게 다른 쓰레드가 해당 자원을 양보
wait()
- 시간값을 넣으면 주어진 시간 이후에 자동으로 실행대기 상태로 전환
- 시간값을 넣지 않으면 일시정지됨
notify()
- wait()로 일시정지 중인 쓰레드를 1개를 실행대기 상태로 전환
notifyAll()
- wait()로 일시정지 중인 모든 스레드를 실행대기 상태로 전환
과제.
공격과 방어를 하는 프로그램을 작성해보자
(단, 쓰레드를 사용)
1. 공격 class를 생성
2. 방어 class를 생성
3. 공격을 하지 않았는데 방어를 할 수 없음
4. 방어를 하지 않았는데 공격을 또 할 수 없음
1번째 공격
1번째 방어
2번째 공격
2번째 방어
...
10번째 공격
10번째 방어
public class Thread1 {
public static void main(String[] args) {
//1.Thread 객체타입의 참조변수안에 바로 상속된애 or 인터페이스구현한애 넣기
Thread th1 = new PrintThread1(); //상속은 한줄! Thread타입의 참조변수안에 상속받았던 클래스의 인스턴스를 넣는다
//상속으로 하면 인자값으로 스레드 이름을 못집어넣네!저 상속클래스안에서 Thread.currentThread().getName()해도 이름 없음
//방법은있다 printThread1안에 문자열 받는 생성자 만들고 getname말고setname으로 설정가능!
//2.인터페이스 상속한애 타입의 참조변수에 상손하애 타입의 인스턴스 만들기
PrintThread1 pt = new PrintThread1(); //그럼 인터페이스구현안 클래스타입의 참조변수안에 그 인터페이스구현한클래스의 인스턴스 못생성하는가?
//생성은 가능하나 인터페이스를 구현했기때문에 run을 상속받지 못해서 start도 안된다
Runnable r1 = new PrintThread2(); //인터페이스를 구현한 클래스의 인스턴스를 인터페이스 타입의 참조변수에 넣는다
//PrintThread2 r1 = new PrintThread2(); //이것도 가능하다
Thread th2 = new Thread(r1); //그 runnable인터페이스를 구현한 클래스의 인스턴스가 들어가있는
// runnable인터페이스타입의 참조변수를 Thread 인스턴스에 인자로 넣어서 생성
//thread 인자로는 빈값 또는 상속받은 클래스의인스턴스 또는 runnable인터페이스를 구현한 클래스의 인스턴스만 넣을수있다
Thread th3 = new Thread(new Thread() { //참조변수 만들기 귀찮으면 바로 익명클래스로 main안에서 구현도 가능
@Override
public void run() {
for(int i=0; i<10; i++) {
if (i % 2 == 0) {
System.out.println("😘 printthread3: " + i);
}
try {
Thread.sleep(1000); //1000 millisecond=1초 sleep은 예외처리해줘야한다
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
th1.start(); //start() 해주면 run() 이 실행된다
pt.start();
th2.start();
th3.start();
for(int i=0; i<10; i++){
if(i%2 ==0){
System.out.println("❤ main: " + i);
}
try{
Thread.sleep(1000); //1000 millisecond=1초 }
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
public class PrintThread1 extends Thread {
//Thread를 상속받아 오버라이딩하는 예제
//원래 run을 구현해야하는데 안하면 jvm이 자동으로 구현해주긴해서 에러는 안나지만 구현따로 해줘야 사용하는 의미가있겠죠?
@Override
public void run() {
for(int i=0; i<10; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() +"✔"+ i);
}
try {
Thread.sleep(1000); //1000 millisecond=1초 }
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class PrintThread2 implements Runnable{
//runnable 인터페이스를 구현!해서 run을 오버라이딩하는 예제
@Override
public void run() {
for(int i=0; i<10; i++) {
if (i % 2 == 0) {
System.out.println("❤ printthread2: " + i);
}
try {
Thread.sleep(1000); //1000 millisecond=1초 }
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Thread2 {
public static void main(String[] args) {
Runnable bank = new Bank(); //Bank같은경우 Thread을 상속받은 클래스이거나 runnable을 구현한 클래스 둘중 하나면 된다
Thread customer1 = new Thread(bank, "김사과"); //첫번째인자는 Tread타입또는 runnable구현한 놈의타입 넣어야함
Thread customer2 = new Thread(bank, "반하나"); //Thread 의 두번째인자는 그 thread의 이름을 지정해준다
Thread customer3 = new Thread(bank, "오렌지");
Thread customer4 = new Thread(bank); //두번째 인자는 name 써도되고 안써도 되는데 안쓰면 thread-# 형식으로 자동입력되어짐
customer1.start();
customer2.start();
customer3.start();
customer4.start();
}
}
public class Bank extends Thread{
private int money = 10000000;
public void withdraw(int money){
this.money -= money;
System.out.println(Thread.currentThread().getName()+"가 " +money +"원 출금");
System.out.println("잔액: " + this.money + "원");
} //공통적인 무언가를 할때는 동기화해줘야함
// 두가지 방법이 있는데 메소드만들때 synchornized 키워드를 넣어주거나
// run 구현시 synchronized(this){} 로 구현부를 감싸거나
// public synchronized void withdraw(int money){
// this.money -= money;
// System.out.println(Thread.currentThread().getName()+"가 " +money +"원 출금");
// System.out.println("잔액: " + this.money + "원");
// } //공통적인 무언가를 할때는 동기화해줘야함
@Override
public void run() {
//synchronized (this){
for(int i=0; i<10; i++){
withdraw(10000);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
//}
}
}
class Runnable1 extends Thread{
@Override
public void run() {
System.out.println("쓰레드1 동작중...");
testThread1();
System.out.println(Thread.currentThread().getName()+"유후냐하");
for(int i=0; i<5; i++){
System.out.println("익명클래스: "+i);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public void testThread1(){
System.out.println("스레드2 동작중...");
testThread2();
}
public void testThread2(){
System.out.println("쓰레드3 동작중...");
}
}
public class Thread3 {
public static void main(String[] args) {// main도 main이라는 스레드 이름을 사용한다는 사실을 알수있다//메인이 항상먼저다
System.out.println(Thread.currentThread().getName() + " Start!");
Runnable1 r = new Runnable1(); //참조변수의 타입을 runnable을 하든 runnable1을 하든 상관없네
//또한 인터페이스를 구현한놈이든 클래스를 상속받은놈이든 어떤놈을 해도 상관없네
Thread b = new Runnable1(); //이런식으로 방법 1 로 만든 스레드도 다시 스레드안에 집어넣을수잇어!
Thread th1 = new Thread(b,"김덕배"); //start를 사용하기위해서 thread에 넣는거네, 이름도 넣을수있네
th1.start(); //다른스레드 시작
try{
th1.join(); //다른 스레드가 종료될때까지 main스레드가 종료되지않고 기다린다
} catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " End!! ");
}
}
public class Thread4 {
public static void main(String[] args) {
Thread thread1 = new Thread(new PrioritySet(),"김사과");
Thread thread2 = new Thread(new PrioritySet(),"김정은");
Thread thread3 = new Thread(new PrioritySet(),"김두한");
//스레드 생성2번째방법(인터페이스구현)인데 첫번째인자로 Runnable인터페이스를 구현한 클래스의 인스턴스가 들어간 Runnable타입의 참조변수를 넣었는데=
//Extends thread 한 클래스의 인스턴스를 넣어도 결과는 똑같다.
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.NORM_PRIORITY);
thread3.setPriority(Thread.MIN_PRIORITY);
//당연히 실행전에 우선순위를 설정해줘야함
thread1.start();
thread2.start();
thread3.start();
}
}
public class PrioritySet implements Runnable{
@Override
public void run() {
String name = Thread.currentThread().getName();
int priority = Thread.currentThread().getPriority();
System.out.println(name + ">" +priority);
}
}
public class Thread5 {
public static void main(String[] args) {
ThreadA a= new ThreadA();
// threadA안에 다른 필드도 있어 그래서 기존의 Thread 타입으로 넣으면 업캐스팅이되면서 자식클래스들의 필드는 사용하지 못하게된다
// 그래서 그냥 자식 타입의 참조변수안에 자식타입의 클래스를 넣어준다 이떄 그 클래스는 Thread 상속을 받은 클래스여야하고
// 인터페이스 를 구현한 클래스는 start가 상속되지않아서 없기때문에 사용을 할수가 없다
ThreadB b= new ThreadB();
a.start(); //이게 되는 이유는 자식클래스에 thread를 상속받아 start를 물려받았기때문 그래서 runnable구현한놈은 사용X
b.start();
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
//a가 멈춤
a.work = false;
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
//a가 일을 재개
a.work = true;
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
//b가 일을 멈춤
b.work = false;
//a,b 모두 멈춤
a.work = false;
a.stop=true;
b.stop=true;
}
}
public class ThreadA extends Thread{
boolean stop = false;
boolean work = true;
@Override
public void run() {
while(!stop){
if(work){
System.out.println("ThreadA ^^");
try{
Thread.sleep(500);
}catch(InterruptedException e){
e.printStackTrace();
}
}else{
Thread.yield(); // 본 스레드는 양보를 하겟다~~
}
}
System.out.println("ThreadA 종료!");
}
}
public class ThreadB extends Thread{
boolean stop = false;
boolean work = true;
@Override
public void run() {
while(!stop){
if(work){
System.out.println("ThreadB ^^");
try{
sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}else{
Thread.yield();
}
}
System.out.println("ThreadA 종료!");
}
}
영어단어장 예제
import java.util.ArrayList;
import java.util.Scanner;
public class WordMain {
public static void main(String[] args) {
System.out.println("영어단어장");
System.out.println("print: 출력");
System.out.println("find: 검색");
System.out.println("save: 저장");
System.out.println("exit: 종료");
Scanner sc = new Scanner(System.in);
WordController wc = new WordController();
wc.setList(new ArrayList<WordM>());
String file ="wordbook.txt";
wc.read(file); //읽어오기
while(true){
System.out.println("영어단어 또는 메뉴를 입력하세요");
String eng = sc.next();
if(eng.equals("exit"))break;
switch (eng){
case "print":
wc.list();
break;
case "find":
if(!wc.find()) System.out.println("찾는 단어가 없습니다");
break;
case "save":
wc.save(file);
break;
default:
wc.insert(eng);
}
}
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;
public class WordController {
private ArrayList<WordM> list;
public ArrayList<WordM> getList() {
return list;
}
public void setList(ArrayList<WordM> list) {
this.list = list;
}
public void insert(String eng){
String kor, wdate;
int lev;
WordM w;
Scanner sc = new Scanner(System.in);
System.out.println("* 뜻을 입력하세요: ");
kor = sc.next();
System.out.println("* 레벨을 입력하세요: ");
lev = sc.nextInt();
System.out.println("* 날짜를 입력하세요: ");
wdate = sc.next();
w = new WordM(eng, kor, lev, wdate);
list.add(w);
}
public void list(){
for(int i=0; i<list.size(); i++){
System.out.println(list.get(i));
}
}
public boolean find(){
Scanner sc = new Scanner(System.in);
boolean isFind = false;
System.out.println("찾는 단어를 입력하세요!");
String find = sc.next();
for(int i=0; i<list.size(); i++){
if(list.get(i).getEnglish().equals(find)) {
System.out.println("단어를 찾았습니다");
System.out.println(list.get(i));
isFind = true;
}
}
return isFind;
}
public void save(String file){
try{
PrintWriter pw =new PrintWriter(new FileOutputStream(file));
for(WordM w: list){
pw.println(w);
}
System.out.println("저장되었습니다");
pw.close();
} catch (FileNotFoundException e){
e.printStackTrace();
}
}
public void read(String file){
Scanner sc= null;
String temp;
String[] arr;
String eng,kor,lev,wdate;
WordM w;
try{
sc = new Scanner(new FileInputStream(file));
while(sc.hasNextLine()){
temp = sc.nextLine();
arr = temp.split(", ");
w = new WordM(arr[0],arr[1], Integer.parseInt(arr[2]), arr[3]);
list.add(w);
}
} catch (FileNotFoundException e){
e.printStackTrace();
}
}
}
public class WordM {
private String english;
private String korean;
private int level;
private String wdate;
public WordM(String english, String korean, int level, String wdate) {
this.english = english;
this.korean = korean;
this.level = level;
this.wdate = wdate;
}
public String getEnglish() {
return english;
}
public void setEnglish(String english) {
this.english = english;
}
public String getKorean() {
return korean;
}
public void setKorean(String korean) {
this.korean = korean;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getWdate() {
return wdate;
}
public void setWdate(String wdate) {
this.wdate = wdate;
}
public String toString(){
// apple, 사과, 1, 2022-10-05
StringBuilder sb = new StringBuilder();
sb.append(english).append(", ").append(korean).append(", ").append(level).
append(", ").append(wdate);
return sb.toString();
}
}
과제
public class Assignment {
public static void main(String[] args) {
CommonMethod cm = new CommonMethod(); //객체를 공유하기위해 생성
Attack attack = new Attack(cm); //같은 객체cm을 공유함
Defence defence = new Defence(cm); //같은 객체cm을 공유함
//힙영역에 생성된 인스턴스의 주소가 담긴 참조변수(cm)를 통해
//하나의 객체를 여러 참조변수(attack)(defence)가 공유할 수 있는거임
attack.start();
defence.start();
}
}
public class Attack extends Thread{
private CommonMethod cm;
Attack(CommonMethod cm){
this.cm = cm;
};
@Override
public void run() {
cm.method1();
}
}
public class Defence extends Thread{
private CommonMethod cm;
Defence(CommonMethod cm){
this.cm = cm;
};
@Override
public void run() {
cm.method2();
}
}
public class CommonMethod {
public synchronized void method1(){
for(int i=1;i<=10;i++){
System.out.println(i+"번째 공격");
notify(); //다른 스레드를 실행대기상태로 변경
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
wait(); //현재 사용중인 스레드를 정지상태로 변경
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void method2(){
for(int i=1;i<=10;i++){
System.out.println(i+"번째 수비");
notify(); //다른 스레드를 실행대기상태로 변경
try {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wait(); //현재 사용중인 스레드를 정지상태로 변경
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
반응형
'서버&백엔드 > 🔥 JAVA' 카테고리의 다른 글
Java,MySQL | JDBC Driver설치,JDBC API연결,Statement (0) | 2022.10.19 |
---|---|
학원1개월차 시험 (0) | 2022.10.17 |
Java | 중첩클래스,예외처리,파일처리 (0) | 2022.10.06 |
Java | 제네릭, 컬렉션프레임워크 (1) | 2022.10.05 |
Java | 래퍼클래스,static,추상클래스,인터페이스,패키지 (1) | 2022.10.04 |