본문 바로가기
IT/JAVA

[16일차] JAVA 예외처리. 스레드

by GWLEE 2022. 7. 11.

2022-07-11 MON

 

inner class 형태

interface도 만들 수 있다.

 

원래 class 

※ 참고 ※ Student.java 파일이 컴파일 => Student.class

                         inner Class 멤버 class => Studnet$Member.class 로 바뀐다.

 

/* Slack에서 주신 것 */

class A{ // 클래스 A 파일 만들고
	class B{ // 클래스 B파일 만든다. => 멤버클래스 
		int field1;
		void method1() {};
		// static 필드 및 메소드는 사용불가
	}
  }

  A a = new A();
  A.B b = a.new B(); // 이런 형태로 만든다.
  b.field1 = 3;
  b.method1();
  
  innerClass가 필요한 순간이 온다.

member Class

local Class

 

class Test {
	public void method() {
    class D{
  		int field1;
  		void method1() {};
  }
  D d = new D();
  d.field1 = 5;
  d.method1();
}

 

 

LocalTest 예시

public class LocalTest {
	public void method(final int arg) {
    final int localVal = 1;

// arg = 10;
// localVal = 100;  이유는 local 변수는 끝나면 stack에서 사라짐
// 

class Inner {
  public void method(){
    int result = arg + localVal;
  } // 여기 사이 update가 되면 안된다. 클로저로 카피할 대상은 final로 붙여놔야한다.
} // closer


  inner in = new Inner();
}
// 언제든지 객체를 만들 수 있는데 클로저라 값을 가지고 있음.
// 값을 복사해 놓고 있는데 객체를 만드는데 문제는 
// 값을 복사해갔는데 나중에라도

 

Button.java


ButtonMain.java

 

Calllistener.jave


 

예외
예외는 다음과 같이 jang.lang 패키지 있는 throwable 클래스의 자식객체로,

프로그램 실행중에 발생하는 일종의 이벤트이다.

 

1. 일반 예외

컴파일러 입장에서 예외가 발생할 수 있는 부분을 판단할 수 있다. 그런 부분은 반드시 예외처리를 해줘야한다.

exception을 상속받아서 만든다. 

개발자의 실수로 발생할 수 있으며, 예외처리를 하지 않아도 컴파일할 수 있는 비검사형 예외이다.

 

 

 

2. 런타임 예외

 

예외처리를 하지 않으면 컴파일 오류가 발생하므로 꼭 처리해야하는 검사형 예외이다. 

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Exception.html

 

Exception (Java SE 11 & JDK 11 )

 

docs.oracle.com

 

 

 

// JVM Java Virtual Machine의 줄인 말 = 자바를 실행시키기 위한 가상 기계(컴퓨터)

// OS에 종속 받지 않고, CPU가 JAVA를 인식, 실행 

 

 

※ 실행 예외 예시 (런타임) 

: 프로그램 실행 도중에 예외가 발생하면 JVM()은 해당 실행 예외 객체를 생성한다. 실행 외는 컴파일러가 예외처리 여부를 확인하지 않기 때문에 개발자가 예외처리 코드의 추가여부를 결정해야한다. 

 

 

 

 NullPointerException 

컴파일러는 알 수가 없어서 에러가 난다. 

null 값을 가진 참조변수에 접근할 때 발생

 

 NullPointerException 

argument를 주지 않아서 발생한다.

배열, 벡터 등에서 범위를 벗어난 인덱스를 사용할 때 발생

 

try - catch 문으로 에러메시지 

catch 블록에 포함된 예외 처리 코드를 핸들러

 

 

ArrayIndexOutOfBoundsException

catch로 에러 표시

printStackTrace()  :  Throwable 객체와 추적 정보를 화면에 출력한다.

 

 

 


※ 일반 예외

컴파일러 입장에서런타임 관계없이 컴파일러가 자체로 막아버리는 일반예외.....

 

Class.forName("jang.lang.String2")

 

실제로는 저렇게 쓰면 안된다. 예외처리를 정확하게 해줘야 한다.

 

 

finally : 예외발생과 관계없이 항상 실행한다.

 

 

public static이 아니라서 localClass에 에러가 뜬다.

그 이유는 메인 메소드가 static으로 올라가는 부분

객체가 생성된 다음에 접근할 수 있는 메소드인데 static안에서 인스턴스 접근이 불가능한데

static에서 static멤버밖에 접근 못하니깐..  static을 사용해야한다.!

 

이렇게 static을 써줘야 ... 


 

throws는 익셉션 던져버리는 거

throws절은 예외를 처리하지 않고 발생한 예외 객체를 다른 곳으로 떠넘긴다.

즉, 현재 메서드에서 예외를 처리하지 않고 발생한 예외 객체를 다른 곳으로 떠넘긴다.

던지면 부모 클래스로 간다. 즉, 현재 메서드에서 예외를 처리하지 않고 현재 메서드를 호출한 곳으로 발생한

예외 객체 대신 처리해달라고 떠넘기는 것이다.

 

 

메서드에서 발생한 예외를 내부에서 처리하기가 부담스러울 때 throws 키워드를 사용해 예외를

상위 코드 블록으로 양도할 수 있다. 

 

메시지 넘긴거

RuntimeException 생성자가 있으니 메시지를 받아서 찍어준다.

throws Bal~~ 에러 발생한 곳에서 잔고부족 던진다. 

 

get 불러오는거 

 

catch 잡히면 빠져나간다.

runtime에 있는 getmessage를 가져온거

 

catch 블록의 예외 객체가 나중 catch 블록 예외 객체의 부모라면, 앞에 있는 catch 블록이 먼저 가로채기 때문에 
나중 catch 블록이 먼저 가로채기 때문에 나중 catch 블록은 쓸모가 없으므로 컴파일러는 오류를 발생시킨다.
따라서, 구체적인 예외를 먼저 처리해야한다.

 


자바의 모든 클래스는 object를 상속 받는데

equals method 오버라이드 

문자열을 비교하게끔 한다.

.equals 를 원하는 상황에 따라 오버라이드 할 수 있다.

 

object 클래스에서 상속받은 equals() 메서드를 사용한다.

따라서 내용이 동일하더라도 다른 객체이기 때문에 false를 반환했던것.

equlas Override를 해야한다.

 

 

Member.java

 

MemberMain.java

 


※ 메소드 오버라이드

instanceof 내장함수 : 복사된 값이냐 

앞에 있는 애가 뒤에 있는 값이 복사값이냐.. 

 

instanceOf 연산자는 객체가 어떤 클래스인지, 어떤 클래스를 상속받았는지 확인하는데 사용하는 연산자입니다.

 

 

equals를 override 한다.

우리가 받아온 obj가 멤버랑 같냐,, 순서 바뀌면 틀린다.

멤버 instance .. new 

m1 == m2 로 나오는데,

m1 != m3


 

 

 

 

자바 연결- C++연결 없어지고 연결 없어지고 연결 

 

계속 쓰다보면 속도가 느려지고 리소스가 많이 사용..

 

 

문자열 내용을 자주 변경한다면 String  클래스를 사용하는 것은 좋지 않다.
string은 불변의 속성을 갖고 있기 때문이다. 
자바는 변경될 수 있는 문자열을 다룰 수 있도록 StringBuilder와 StringBuffer 클래스를 제공한다.
다중 스레드 환경에서 StringBuffer 클래스가 안전하다는 점을 제외하면 StringBuffer 클래스는 StringBuilder 클래스와 유사하다. 다라서 다중 스레드 환경이 아니라면 StringBuilder 클래스를 사용하는 것이 효율적이다.

- StringBuilder 객체는 내부에 문자열을 저장하는 버퍼가 있으며, 그 버퍼의 크기는 변할 수 있다.
매개변수 없는 디폴트 생성자를 사용해 STringBuilder 객체를 생성하면 16개 문자를 저장할 수 있는 버퍼를 생성

---- 검색한 내용

StringBuffer는 동기화 키워드를 지원하여 멀티스레드 환경에서 안전하다는 점(thread-safe) 
 
StringBuilder는 동기화를 지원하지 않기 때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만 동기화를 고려하지 않는 만큼 단일스레드에서의 성능은 StringBuffer 보다 뛰어납니다.

StringBuffer     :  문자열 연산이 많고 멀티스레드 환경일 경우
StringBuilder   :  문자열 연산이 많고 단일스레드이거나 동기화를 고려하지 않아도 되는 경우  

 

 

API를 이용하여 동일 객체내에서 문자열을 변경하는 것이 가능

 

Thread Safe... 스레드 기능..간섭을 안한다.

Buffer를 쓰면 쭉 간다. 중간 사이에 못들어온다.

 


포장클래스 

객체지향 언어는 캡슐화, 상속, 다향성등 특징이 많다. 
그러나 기초 타입을 사용하면, 객체지향언어의 특징을 이용할 수 없다.
대부분의 기본패키지가 제공하는 클래스의 메서드는 참조타입을 매개변수로 사용하기 때문이다.

 

 

기초 타입 데이터를 포장해 객체화하는 것을 박싱이라고 하는데, 반대 과정을 언박싱이라고 한다.

int의 클래스가 Integer.. auto boxing= 같은 데이터 타입을 클래스로 넣어준다.

int와 char 타입에 대응하는 포장 클래스는 각각 Integer와 Character 이며, 나머지 포장클래스 이름은 

기초 타입의 첫 영문자를 대문자로 바꾼 것이다.

 

 

문자열을 정수형

문자열을 더블형으로 바꾸는거 

Integer 자동박싱..

 

 

package com.gyuone.javaapi;

import java.time.LocalDateTime;

public class WrapperExam {
	public static void main(String[] args) {
		Integer a = 100; // 자동으로 넣어주는 auto boxing 이라고한다.
		System.out.println(a);

		// 각각의 wrappe Class 감싸는 클래스를 만들었다.
		// Byte Char Integer Short .... 이미 클래스를 만들어놨음

		int val1 = Integer.parseInt("10"); // 문자열을 바꾸는 거
		val1++;
		System.out.println(val1);

		double val2 = Double.parseDouble("3.14");
		val2 *= 10;
		System.out.println(val2);
		
		LocalDateTime now = LocalDateTime.now();
		System.out.println(now);
		
		StringBuilder sb = new StringBuilder();
		sb.append(now.getYear());
		sb.append("년 ");
		sb.append(now.getMonthValue());
		sb.append("월 ");
		sb.append(now.getDayOfMonth());
		sb.append("일 ");
		sb.append(now.getDayOfWeek());
		sb.append(" ");
		sb.append(now.getHour());
		sb.append("시 ");
		sb.append(now.getMinute());
		sb.append("분 ");
		sb.append(now.getSecond());
		sb.append("초 ");
		sb.append(now.getNano());
		sb.append("나노초");
		System.out.println(sb.toString() + "\n");

	}
}

import 해주기 ! slack 에서 보내주신거


스레드 : 한 가닥의 실


: 작업을 실행하는 코드의 흐름이 바느질할 때의 실처럼 이어진 것과 같기 때문이다. 

하나의 프로세스는 하나 이상의 실행흐름을 포함시키기 때문에 프로세스는 적어도 하나의 스레드를 가진다.

 

 

 

 

프로그램 하나 띄우는 거  OS 입장에서 보면 프로세스(process)

프로세스랑 스레드랑 다르다.. 스레드는 스레드끼리 메모리공유

 

메모장을 클릭하면, 하나의 프로세스를 실행시킨다는 의미

그런데 하나의 프로세스가 시스템 자원을 독차지하는 것은 매우 비효율적임.

 

 

메인 스레드가 하는 역할이 static영역의 thread ..

단일 스레드 형태로 메인 스레드가 동작 

 


Thread 만드는 첫 번째 방법
: 자바 내장된 Thread 사용

 

FlagGame.java

 

FlagThread.java

자바 내장된 Thread 사용

 

문제점 : 다른 것을 extends 해야하는 상황이 생긴다면,

자바에서는 다중 상속이 안되기 때문에 보완하기 위해서는 다른 방법이 필요하다. -> 이때는 interface 사용

 

 


Thread 만드는 두 번째 방법
: Runnable 구현 클래스 정의



Runnable 구현 클래스에 스레드 실행 코드 추가...

 

 

FlagTask.java

FlagGame2.java

Runnable 구현 클래스 구현  정의

 

 


Runnable 구현 클래스에 스레드 실행 코드 추가

 

FlagThread.java

Runnable 인터페이스의 익명 구현 객체 사용!

 

FlagGame2.java

Runnable 인터페이스의 익명 구현 객체 

 

 


스레드를 상속한 익명 자식객체..
Thread 자식 클래스 정의


thread.start();

스레드를 위한 자식 클래스가 정의되면 다음과 같이 자식 객체를 생성한다. 그런 다음 Thread 클래스의 메서드인 start()를 호출하면 작업스레드가 실행될 수 있다. 

 

 

둘다 익명 자식객체. 익명 구현객체를 만들 수 있다.

 


스레드 이름 지정 

ThreadA

setName으로 스레드 이름 지정

ThreadB

스레드이름을 지정 X 오버라이드만 허용..

 

스레드 이름을 지정해주지 않으면 Thread-1로 나온다. 스레드 이름을 지정해주면 디버깅하기 편하다.

 


 

Calculator.java

 

User1.java

 

User2.java

 

CalMain.java

 

두개의 스레드가 근소한 차이가 실행이 되면 

Calculator 본인 스레드 이름을 각자 정하고 setMemory에 넣는다.

user1이 100 setting 필드 값 100 넣기

 시간이 잡아 먹는 일을 하다가 50이 넣어오면 syso에 50이 넣어서 

override된거 맞음.. setMemory에서 빠져나오지 못해서 발생..

 

두개 이상의 Thread가 동시에 진행.. -> 문제가 생길 수 있는 부분을 critical section

-> 다른 작업이 들어오지 못하게 막는다. 제일 간단한 방법

 

 

Calculator.java

synchronized : 이 키워드의 존재 여부에 따라 user1이 먼저 실행 되고 나서 user2가 다음에 실행된다.

작업1을 하고 작업2를 해서 시간이 조금 걸린다.

자바는 임계영역을 동기화하려고 synchronized 키워드를 제공한다. 스레드가 synchronized로 지정된 동기화 블록에 진입하면 lock을 걸고, 그 블록을 벗어날 때 lock을 푼다. 동기화 블록에 진입한 스레드가 코드를 실행할 동안 다른 스레드는 동기화 블록 앞에서 락이 풀릴때까지 대기해야한다. 그러므로 스레드 동기화는 하나의 스레드가 동기화 블록을 실행하면 그 스레드가 동기화 블록을 사용하려는 모든 스레드를 중지시킨다.

 메서드에 키워드를 지정하거나 코드의 일부에 지정한다. 메서드 전체가 아니라 일부 영역만 임계 영역이라면 동기화 블록을 사용하는 것을 좋다. 

 

 

 

멀티 스레드 환경에서도 안전하게 사용가능

StringBuilder 

StringBuffer 사용법은 같다.

StringBuffer <= thread safe 방법이다.

 

Calculator.java

 

String을 받아서 사용가능하지만 귀찮으니 this를 쓰자. 강사님께서는 this를 쓰라고 하셨다.

 

 

 

 

 


리소스 문제로 막아버림

 

스레드의 종료 여러가지 방법

방법1_ 무한루프로 돌고 있는 스레드를 안전하게 종료시키는 방법
stop flag를 걸어서 빠져 나온다.

 

 

stop() 메서드를 사용할 수 있지만, 호출 즉시 종료하므로 사용중인 자원을 불완전한 상태로 남겨 둔다.
따라서, 자바2부터는 stop() 메서드를 가급적으로 사용하지 않도록 권고한다.
스레드를 안전하게 종료하려면 반복문의 조건이나 interrupt() 메서드를 사용하지 않는 것이 좋다.

 

 

 

PrintThread.java

PrintMain.java

Console

 

돌던 거에 상태를 어디에 저장 t8 -> t1 다시 로드해서 돌려야한다.

context switching 이것도 오버헤드가 걸린다. -> 시간이 오래걸림 .. 성능 떨어진다.

소프트웨어 상식으로 알아두기~

 


방법2_ 인터럽트를 걸어서 thread 종료하는 방법 

 

 

인터럽트 : 강제로 끼어드는 것을 의미

while문 계속 돌다가 인터럽트 만나면 빠져나감

인터럽트에 걸리려면 sleep을 줘야한다. 최소한의 sleep 1을 준다.

thread가 sleep일때만 인터럽트를 잡을 수 있다.

 

 

PrintMain2.java

 

PrintThread2.java

 

Console

 

 


 

방법3_ while문을 통해서 break 
thread 종료


 

PrintThread3.java

 

PrintMain3.java

 

Console


 

데몬 스레드

일반적으로 스레드는 독립적으로 수행되기 때문에 메인 스레드를 종료해도 작업 스레드는 계속 실행된다.
그런데 어떤 스레드는 다른 스레드의 보조 작업을 수행하기 때문에 주된 스레드를 종료하면
더이상 존재할 이유가 없다. 이처럼 다른 스레드가 종료되면 자동으로 종료되어야하는 스레드를 데몬 스레드라고 하는데, 우선 순위가 가장 낮다.



 

DemonThread.java

 

DemonMain.java

Console

'IT > JAVA' 카테고리의 다른 글

[17일차] JAVA Programmers 개념정리  (0) 2022.07.12
[17일차] JAVA Generic / lambda  (0) 2022.07.12
[15일차] JAVA Programmers 개념정리  (0) 2022.07.08
[15일차] JAVA  (0) 2022.07.08
[14일차] JAVA 객체지향  (0) 2022.07.07

댓글