• 검색 결과가 없습니다.

예외처리와 스레드

N/A
N/A
Protected

Academic year: 2022

Share "예외처리와 스레드"

Copied!
51
0
0

로드 중.... (전체 텍스트 보기)

전체 글

(1)

1

(2)

예외처리와 스레드

[ 단원 08 ]

(3)

단원 08 예외처리와 스레드

학습목표

❖ 예외와 예외처리를 이해하고 프로그래밍에 활용할 수 있다.

• 에러와 예외의 차이와 클래스 계층구조

• 체크 예외와 비체크 예외의 차이와 처리 방법

• 새로운 예외 클래스의 생성과 사용 방법

❖ 스레드를 이해하고 스레드를 프로그래밍에 활용할 수 있다.

• 다중 작업과 스레드의 이해

• 클래스 Thread를 상속받아 처리하는 스레드 구현

• 인터페이스 Runnable을 구현하여 처리하는 스레드 구현

❖ 스레드 상태와 우선순위, 동기화를 이해하고 프로그래밍에 활용할 수 있다.

• 스레드 상태와 전이 방법

• 스레드 우선순위의 지정 방법

• 스레드에서 자원의 공유 문제와 동기화 처리

• Object의 wait( )와 notify( )를 사용한 동기화

3

(4)

단원 08 예외처리와 스레드

4

1. 예외처리 개요

(5)

단원 08 예외처리와 스레드

예외와 에러

❖ 자바에서 오류: 에러(error)와 예외(exception)로 구별

예외

자바 프로그램에서 실행 중에 발생할 수 있는 경미한 오류를 예외

적절한 처리 모듈을 추가하여 발생한 문제를 복구 가능

IndexOutOfBoundsException과 같이 ◯ ◯ ◯ Exception 형태

에러

메모리나 내부의 심각한 문제

복구가 불가능한 오류인 OutOfMemoryError, InternalError 등

에러와 예외를 모두 객체로 만들어 처리, 관련 클래스 계층 구조

클래스 Throwable

– 하부로 예외인 Exception 클래스와 에러인 Error 클래스

Exception 클래스 하부

– 다양한 예외를 위한 클래스

5

Section 1 예외처리 개요 p302

(6)

단원 08 예외처리와 스레드

다양한 예외의 발생

❖ 예외가 발생하면

바로 프로그램이 중단되므로 발생한 이후의 프로그램을 실행되지 않음

발생한 예외 클래스의 이름과 예외가 발생한 프로그램 소스와 줄 번호가 표시

NullPointerException

실제 변수에 저장된 객체가 null임에도 불구하고 객체의 멤버를 참조하려는 경우 발생

ArrayIndexOutOfBoundsException

배열에서 배열의 첨자 범위를 벗어난 첨자 사용

ArithmeticException,

0으로 수를 나누려 할 때 발생

ArrayStoreException

배열에 잘못된 유형의 객체를 저장하려 할 때 발생

ClassCastException

객체를 변환할 수 없는 유형으로 변환하려고 할 때 발생

NegativeArraySizeException

배열의 크기를 음수로 지정하는 경우 발생

6

Section 1 예외처리 개요

(7)

단원 08 예외처리와 스레드

실습예제

❖ 8-1, 8-2

7

Section 1 예외처리 개요

(8)

단원 08 예외처리와 스레드

예외처리 구문 try

❖ 예외처리(exception handling)

실행 중에 여러 이유로 예상하지 못했던 문제가 발생한 경우 이를 적절히 처리하는 모듈

❖ 예외처리 모듈

try ~ catch ~ finally 문장

예외 발생과 상관없이 finally의 블록은 실행

catch와 finally 둘 중 하나는 옵션

8

Section 1 예외처리 개요

(9)

단원 08 예외처리와 스레드

실습예제

❖ 8-3

try 내부에서 예외가 발생하면

더 이상 try 블록 내부의 나머지 문장은 실행하지 않음

9

Section 1 예외처리 개요

(10)

단원 08 예외처리와 스레드

catch 처리 순서

❖ 여러 개의 catch 문을 이용하는 경우

프로그램이 실행되는 순간에 예외가 발생하면

여러 개의 catch 문 중에서 위에서부터 순차적으로 catch(ExceptionType var) 문 에서 ExceptionType 인자 유형을 검사

발생된 예외의 유형과 일치하거나 하위 클래스이면 먼저 만나는 catch 문 블록만을 실행

주의할 점

여러 개의 catch
 구문에 기술하는
 ExceptionType이
 하위 클래스인 


것부터 먼저 catch
 블록을 기술

10

Section 1 예외처리 개요

(11)

단원 08 예외처리와 스레드

실습예제 8-4

11

Section 1 예외처리 개요

예외 참조 변수인 e를 바로 출력하면 예외 클래스 이름과 메시지가 출력

발생한 예외의 메시지만 알아보려면 e.getMessage() 메소드를 사용

예외 처리를 하지 않은 경우 출력되는 모든 메시지를 보려면 e.printStackTrace() 메 소드를 사용

모든 예외 클래스는 Exception의 하위 클래스이므로 Exception 유형 의 참조변수 catch 블록은 모든 종류의 예외를 처리할 수 있으므로 반드 시 catch 블록의 마지막에 배치

(12)

단원 08 예외처리와 스레드

12

2. 체크 예외와 예외 생성

(13)

단원 08 예외처리와 스레드

예외 계층 구조

❖ RuntimeException

그 하부 예외

ArithmeticException, NullPointerException,

ArrayIndexOutOfBoundsException, IndexOutOfBoundsException

13

Section 2 체크 예외와 예외 생성 p308

(14)

단원 08 예외처리와 스레드

비체크 예외와 체크 예외

❖ 비체크 예외(unchecked exception)

RuntimeException과 그 하부 예외가 발생할 가능성이 있는 코드들은 try ~ catch 문이 선택적

RuntimeException, ArithmeticException, NullPointerException

❖ 체크 예외(checked exception)

예외 중에서 RuntimeException과 그 하부 예외를 제외한 모든 예외

FileNotFoundException

– 존재하지 않는 파일을 처리

ClassNotFoundException

사용하려는 클래스의 이름을 잘못 기술

DataFormatException

입력한 데이터의 형식이 잘못

14

Section 2 체크 예외와 예외 생성

(15)

단원 08 예외처리와 스레드

체크 예외

❖ 클래스 Class

클래스 Object의 하위 클래스로 응용 프로그램에서 실행 중인 클래스나 인터페이 스를 대표하는 클래스

Class의 메소드 중에 정적 메소드인 forName(className)

인자인 className의 객체를 반환하는 메소드

인자인 className의 클래스가 없다면

– ClassNotFoundException 예외를 발생

forName(className)을 호출하는 부분에서 반드시 예외처리를 수행

– 아니면 컴파일 에러 발생

15

Section 2 체크 예외와 예외 생성

(16)

단원 08 예외처리와 스레드

실습예제

❖ 8-5

❖ 메소드의 예외 확인

메소드 선언을 살펴보면 발생할 수 있는 예외를 알 수 있음

발생하는 예외가 체크 예외라면 메소드 호출 부분에서 예외처리가 없으면

– 컴파일 시간에 문법 오류가 발생

16

Section 2 체크 예외와 예외 생성

(17)

단원 08 예외처리와 스레드

체크 예외의 2가지 처리방법

❖ 첫 번째 방법

try~catch 구문 사용 방법

17

Section 2 체크 예외와 예외 생성

public class TryCheckedException {

public static void main(String[] args) {

//메소드 Class.forName()을 사용하려면 반드시 예외처리를 해야 함 try {

System.out.println(Class.forName("java.lang.Object"));

} catch (ClassNotFoundException ex) { System.out.println(ex);

} } }

(18)

단원 08 예외처리와 스레드

18

❖ 두 번째 방법

예외가 발생될 수 있는 구문이 속한 메소드에서 다시 예외를 전달(propagation) 하는 방법

상위 메소드로 예외처리를 미루는 방법

public class PropagateCheckedException {

//메소드 선언에서 다시 예외 ClassNotFoundException의 발생을 전달

public static void main(String[] args) throws ClassNotFoundException {

//메소드 Class.forName()을 사용하려면 반드시 예외처리를 해야 함

System.out.println(Class.forName("java.lang.Object"));

} }

(19)

단원 08 예외처리와 스레드

예외 클래스 생성과 발생

❖ 새로운 예외 클래스 정의

Exception 을 상속받아 구현

생성자에서 super(msg)로 구현

msg에 저장된 문자열은 메소드
 getMessage()에 의해 반환

❖ 생성된 예외의 발생

생성된 예외 클래스는 필요한 경우 예외를 발생(throws) 가능

예외를 발생시키는 부분에서는 new MyException("내가 만든 예외")

메소드 선언에서 throws MyException을 기술

발생되는 예외가 여러 개라면 여러 예외 유형을 쉼표로 구분하여 기술

19

Section 2 체크 예외와 예외 생성

(20)

단원 08 예외처리와 스레드

실습예제 : 새로운 예외의 처리

❖ 8-9

super(msg)를
 구현하지 않았다면

getMessage()는
 null을 반환

20

Section 2 체크 예외와 예외 생성

(21)

단원 08 예외처리와 스레드

21

3. 스레드 개요

(22)

단원 08 예외처리와 스레드

스레드(thread)

❖ 프로그램 내에서 실행되는 프로그램 제어 흐름

프로그램의 내부의 실행 흐름인 스레드를 여러 개 만들 수 있다면

여러 일을 동시에 처리하는 듯한 느낌

22

Section 3 스레드 개요 p314

(23)

단원 08 예외처리와 스레드

다중 작업과 다중 스레드

❖ 다중 스레드(multi-thread) 프로그램

여러 개의 스레드를 이용하는 프로그램

❖ 스레드

가벼운 프로세스(light-process)

장점

하나의 프로그램 내부에서 실행되는 스레드 는 프로세스보다 오버헤드가 적으면서 처리 할 작업을 동시에 실행

23

Section 3 스레드 개요

❖ 다중 작업(multi-tasking)

여러 프로그램을 동시에 실행시켜 서 로 이동하면서 작업이 가능

❖ 프로세스(process) 란?

실행되고 있는 프로그램

프로세스마다 고유한 저장공간을 사용 하며 독립적으로 실행

단점

여러 프로세스를 실행하려면 프로세스 간의 정보 교환에 많은 시간이 소요

(24)

단원 08 예외처리와 스레드

스레드를 처리하는 첫 번째 방법

❖ 클래스 Thread를 상속받아 구현하는 방법

클래스 Thread를 상속받아 새로운 스 레드를 정의

Thread의 메소드 run()에서 스레드 작업을 재정의

단점

다른 클래스를 상속받아야 하는 경우 이용할 수 없음

실행 방법

객체를 생성한 후 메소드 start()를 호 출하여 스레드를 시작

– 메소드 start()의 호출에 의해 스레드 에 재정의된 run()이 수행

24

Section 3 스레드 개요

(25)

단원 08 예외처리와 스레드

스레드의 주요 메소드

25

Section 3 스레드 개요

(26)

단원 08 예외처리와 스레드

실습예제 8-10

❖ 1 에서 9까지 출력하는 스레드

26

Section 3 스레드 개요

SimpleThread.java

(27)

단원 08 예외처리와 스레드

스레드 이름 지정과 반환

❖ 이름을 가진 스레드를 생성

메소드 setName()을 사용

❖ 지정된 스레드의 이름을 반환

메소드 getName()을 사용

❖ 스레드를 잠시 멈추게 하려면

sleep(시간)을 이용, 지정된 인자는 천분의 1초

27

Section 3 스레드 개요

(28)

단원 08 예외처리와 스레드

실습예제 8-11

28

Section 3 스레드 개요

class IncThread extends Thread {

//생성자 구현

public IncThread(String name) {

setName(name); //생성자 이름 지정 }

public void run() {

for (int i = 1; i < 5; i++) { try {

sleep(50); // 50/1000 초 대기

System.out.print(getName() + ": " + i);

System.out.println(", 활성화된 스레드 수: " + activeCount());

} catch (Exception e) { e.printStackTrace();

} } } }

class DecThread extends Thread { public void run() {

for (int i = 5; i > 1; i--) try {

sleep(50); // 50/1000 초 대기

, 2000(2초)으로 수정가능

System.out.print(getName() + ": " + i);

System.out.println(", 활성화된 스레드 수: " + activeCount());

} catch (Exception e) { e.printStackTrace();

} }

}

(29)

단원 08 예외처리와 스레드

29

public class ThreadTest {

public static void main(String[] args) {

IncThread inc = new IncThread("증가 스레드");

inc.start();

DecThread dec = new DecThread();

dec.start();

}

}

(30)

단원 08 예외처리와 스레드

인터페이스 Runnable

❖ 인터페이스 Runnable

추상 메소드 run()으로 구성된 단순한 인터페이스

스레드로 실행하려는 클래스

인터페이스 Runnable을 상속받아 메소드 run()에서 스레드 기능을 구현

❖ 클래스 Thread

Thread는 인터페이스 Runnable을 상속받아 메소드 run()을 재정의

30

Section 3 스레드 개요

package java.lang;

 

public interface Runnable {

public abstract void run();

}

public class Thread implements Runnable {

}

(31)

단원 08 예외처리와 스레드

스레드를 처리하는 두 번째 방법

❖ 인터페이스 Runnable의 run( ) 메소드 구현

스레드의 이름 반환

Thread.currentThread().getName()을 호출

❖ 스레드를 시작

구현한 스레드의 객체 인자로 Thread를 생성

스레드 시작 메소드 start()를 호출

31

Section 3 스레드 개요

(32)

단원 08 예외처리와 스레드

실습예제 8-12

32

Section 3 스레드 개요

(33)

단원 08 예외처리와 스레드

33

4. 스레드 상태와 우선순위

(34)

단원 08 예외처리와 스레드

스레드 상태 6가지

❖ 스레드의 상태

클래스 Thread 내부에 enum State으로 선언

스레드는 객체가 생성되면 NEW라는 상태

start()가 호출되면 RUNNABLE 상태로 이동

34

Section 4 스레드 상태와 우선순위 p322

(35)

단원 08 예외처리와 스레드

스레드 상태 전이

❖ NEW : 스레드는 객체가 생성되면 이동되는 상태

❖ RUNNABLE : 메소드 start()가 호출되면 이동

❖ TERMINATED : 스레드가 완전히 종료된 상태

더 이상 NEW 또는 RUNNABLE 등의 다른 상태로 전이가 불가능한 상태

❖ BLOCKED, WAITING, TIMED_WEIGHTING

35

Section 4 스레드 상태와 우선순위

(36)

단원 08 예외처리와 스레드

스레드 우선순위

❖ setPriority()

스레드의 우선순위 지정

❖ getPriority()

현재 값을 반환

❖ 스레드의 우선순위

1에서 10까지 지정 가능

36

Section 4 스레드 상태와 우선순위

(37)

단원 08 예외처리와 스레드

실습예제 8-13

❖ 스레드 우선순위는 특별히 지정하지 않으면

상수 NORM_PRIORITY의 값인 5

37

Section 4 스레드 상태와 우선순위

public class ThreadState implements Runnable { public void run() {

for (int i = 1; i < 10; i++) { try {

Thread.sleep(40);

System.out.print(Thread.currentThread().getState() + ",

");

System.out.println(Thread.currentThread().getName() + ":

" + i);

} catch (InterruptedException e) {

System.err.pprintln("InterruptedException이 발생되어 스레드를 종료합니다. ");

return;

} catch (Exception e) { e.printStackTrace();

} } }

public static void main(String[] args) throws InterruptedException {

System.out.println("스레드의 모든 상태: 6 가지");

for (Thread.State c : Thread.State.values()) System.out.print(c + " ");

System.out.println('\n');

Thread th = new Thread(new ThreadState());

System.out.println("기본 우선순위: " +

th.getPriority());

(38)

단원 08 예외처리와 스레드

38

5. 스레드 동기화

(39)

단원 08 예외처리와 스레드

다중 스레드의 문제

❖ 다중 스레드 상에서 공유 자원의 처리 문제

예상하지 못한 문제 발생 가능성 존재

스레드 A가 공유 자료를 처리하는 도중에

다른 스레드 B가 그 자료를 처리한다면

– 다중 스레드에서 수행해야 할 작업이 하나의 단위로 처리되지 않아서 발생할 수 있는 문제

39

Section 5 스레드 동기화 p326

(40)

단원 08 예외처리와 스레드

다중 스레드 구현

❖ 은행 계좌 모의 구현

신청한 금액을 인출하는 메소드 withdraw()

신청한 금액을 입금하는 메소드 deposit()

❖ 인터페이스 Runnable을 상속받는 스레드

클래스 SyncTest는 은행계좌 객체 act 하나를 사용하여 20000원 이하의 금액에 대하여

입금(deposit)과 출금(withdraw)을 반복 처리

withdraw()는 어떠한 경우에도 잔고가 음수가 발생하지 않도록 의도

만일 계좌의 잔고가 0원 미만이면 계좌에 문제가 발생한 것이므로 스레드를 종료

40

Section 5 스레드 동기화

public class SyncTest implements Runnable { BankAccount act = new BankAccount();

 

public void run() { while (true) {

int amount = new Random().nextInt(10000);

act.deposit(amount);

act.withdraw(amount*2);

if (act.balance < 0) {

System.out.printf("[%s] ", Thread.currentThread().getName());

System.out.println("잔고: " + act.balance + " => 오류 종료");

return;

} } }

}

(41)

단원 08 예외처리와 스레드

다중 스레드의 임계 영역

❖ 임계영역(critical section)

다중 스레드에서 하나의 스레드가 배타적(exclusive)으로 공유 자원을 독점하도록 해야 하는 부분

❖ 임계영역의 실례

하나의 스레드가 은행계좌의 인출 메소드 withdraw() 기능을 수행

중간에 다른 스레드가 들어와 일을 할 수 없도록 잠금(lock) 장치 필요

인출 기능을 모두 수행했다면 다른 스레드가 일을 하도록 잠금 장치를 해지(unlock) 해 야 할 것

즉 다음 소스에서 1, 2, 3 세 개의 문장은 독점적인 실행 필요

41

Section 5 스레드 동기화

(42)

단원 08 예외처리와 스레드

동기화

❖ 스레드 동기화(thread synchronization)

다중 스레드에서 임계영역의 독점적 처리 해결 방법

❖ 동기화 방법 크게 2가지

메소드의 동기화

메소드의 동기화는 메소드의 지정자인 키워드 synchronized를 기술

블록의 동기화

블록의 동기화는 synchronized (Object) {…}

여기서 Object는 잠금 장치를 수행하는 객체

42

Section 5 스레드 동기화

(43)

단원 08 예외처리와 스레드

은행계좌의 동기화 문제

❖ 임계 영역에서 자원의 공유로 인한 문제

두 스레드 Thread-0와 Thread-1

동기화가 구현되지 않은 메소드 withdraw()에서 발생하는 문제

두 스레드가 각각 인출을 수행하므로 잔고가 음수가 되는 문제가 발생

43

Section 5 스레드 동기화

(44)

단원 08 예외처리와 스레드

44

Section 5 스레드 동기화

package synchronize;

 

import java.util.Random;

 

class BankAccount { int balance = 0;

 

//메소드 전체의 동기화 처리

public synchronized void withdraw(int money) { if (money > 0 && balance >= money) {

balance -= money;

System.out.printf("%d 인출하여 현재잔고 %d입니다. %n", money, balance);

} else if (balance < money)

System.out.println("잔고가 부족하여 인출할 수 없습니다.");

}  

//블록 동기화로 메소드 전체의 동기화 처리

public void deposit(int money) {

synchronized (this) { if (money > 0) {

balance += money;

System.out.printf("%d 입금하여 현재잔고 %d입니다. %n", money, balance);

} } } }

(45)

단원 08 예외처리와 스레드

45

 

public class SyncTest implements Runnable {

BankAccount act = new BankAccount();

 

public void run() {

//while (true) {

for (int i = 0; i < 3; i++) {

int amount = new Random().nextInt(10000);

amount = amount % 10 * 1000;

System.out.printf("[%s]

금액=%d %n"

, Thread.currentThread().getName(), amount);

act.deposit(amount);

act.withdraw(amount * 2);

if (act.balance < 0) {

System.out.printf("[%s] ", Thread.currentThread().getName());

System.out.println("잔고: " + act.balance + " => 오류 종료");

return;

} } }  

public static void main(String[] args) {

Runnable r = new SyncTest();

new Thread(r).start();

new Thread(r).start();

} }

(46)

단원 08 예외처리와 스레드

메소드 wait( )와 notify( ), notifyAll( )의 이해

❖ Object 의 메소드 wait()와 notify(), notifyAll()을 사용

스레드 동기화에서 동기화 효율을 높이는 방안

메소드 wait()

동기화 블록에서 객체의 특정한 작업을 위해 처리 중인 스레드를 WAITING 또는 TIMED_WAITING 상태로 이동

notify() 또는 notifyAll()

다시 스레드 상태를 RUNNABLE로 이동시켜 스레드 작업을 다시 수행 시킴

특징

Object 클래스의 메소드이므로 모든 객체에서 사용 가능

키워드 synchronized를 사용하는 동기화 내부에서만 사용 가능

46

Section 5 스레드 동기화

(47)

단원 08 예외처리와 스레드

메소드 wait( )와 notify( ), notifyAll( )의 사용

❖ 메소드 wait()

❖ notify() 또는 notifyAll()

47

Section 5 스레드 동기화

(48)

단원 08 예외처리와 스레드

48

Section 5 스레드 동기화

package wait;

import java.util.Random;

class BankAccount { intbalance = 0;

intdiff = 0;

publicsynchronizedvoid withdraw(int money) { if (money < 0) {

System.out.println("인출 금액이 잘못됐습니다.");

return;

}int count = 0;

while (balance < money) {

System.out.printf("[%s] ", Thread.currentThread().getName());

// 지속적으로 잔금이 부족하여 메소드 종료 if (++count > 3) {

System.out.println("잔액이 부족하여 출금처리 못하고 종료합니다.");

return;

}

System.out.printf("%16s", "wait(1000) 호출: ");

System.out.printf("인출요구금액=%6d, balance=%6d %n", money, balance);

try {

// wait();

wait(1000);

}catch (InterruptedException e) { System.err.println(e);

} }

System.out.printf("[%s] ", Thread.currentThread().getName());

balance -= money;

System.out.printf(" %12s 정상인출금액=%6d, balance=%6d %n", "정상 출금처리:", money,balance);

}

publicsynchronizedvoid deposit(int money) { if (money < 0) {

System.out.println("입금 금액이 잘못됐습니다.");

return;

}balance += money;

System.out.printf("[%s] ", Thread.currentThread().getName());

System.out.printf("%16s", "notify() 호출: ");

System.out.printf("계좌입금금액=%6d, balance=%6d %n", money, balance);

// notify();

notifyAll();

} }

(49)

단원 08 예외처리와 스레드

49

publicclass SyncTest implements Runnable { BankAccountact = new BankAccount();

publicvoid run() {

for (int i = 1; i < 3; i++) {

int amount = (int) (new Random().nextDouble() * 5 + 1) * 10000;

act.deposit(amount);

amount = (int) (new Random().nextDouble() * 5 + 1) * 10000;

act.withdraw(amount);

} }

publicstaticvoid main(String[] args) { Runnable r = new SyncTest();

new Thread(r).start();

new Thread(r).start();

} }

(50)

50

(51)

[ Add your company slogan ]

Thank You !

참조

관련 문서

• 다중 스레드 방식은 하나의 프로세스 안에 여러 개의 스레드가 있으므로 지금 실행되는 스레드에서 입출력 명령이 발생해서 더 이상 스레드가 실행되지 못하는

종축을 관통하는 선형공급곡선은 모든 점에서 탄력적 è 점탄력성 (point elasticity)의 측정. 종축을 관통하는 선형공급곡선은

• 공급망 내의 모든 당사자들이 거래에 필요한 정보를 사전 또는 적시에 받을 수 있고 그러한 정보를 별도의 처리나 가공 없이 업무에 그대로 사용할 수 있으므로 정보

자바에서 처리하는 예외는 모두 Exception 클래스에서 파 Exception 클래스는 Throwable 클래스의 하위 클래스임 결국 모든 예외 클래스가 Throwable의 하위

(b) 모선 1에서 0Ω의 임피던스를 갖는 3상 단락회로(bolted fault)에 대해 차과도 고장전류와 송전선 로에 의한 고장전류를 Z

이유로는 모태에서의 공간적 제한을 받다가 출생에 의한 해제로 지금까지의 발육지연에 대한 따라잡기 현상(catch up)과 과대보상기전에 따른

- 학교 내에서 발생한 안전사고의 경우 교육활동 과의 관련성 여부와는 별개로 피해 학부모가 가 해학생의 학부모보다는 학교장이나 담당교사에 게 책임을 전가하고

재료들의 배치 기능들의 배치 장소들의 배치 사건들의 배치 건축물의 배치