문제 1: 다음 코드에서 전화를 걸기 전에 메시지를 먼저 보낼까요? 메시지 전송
public class A {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
// 락 적용
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone.makeCall(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
class Phone {
// synchronized는 메서드 호출자에 대한 락
// 두 메서드는 동일한 락 사용, 먼저 획득한 스레드가 실행
public synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
public synchronized void makeCall() {
System.out.println("전화 걸기");
}
}
문제 2---두 개의 객체로 변경했을 때, 전화를 걸기 전에 메시지를 먼저 보낼까요? 전화 걸기
public class A {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
// 락 적용
new Thread(()->{
try {
phone1.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone2.makeCall(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
class Phone {
// synchronized는 메서드 호출자에 대한 락
// 두 메서드는 동일한 락 사용, 먼저 획득한 스레드가 실행
public synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
public synchronized void makeCall() {
System.out.println("전화 걸기");
}
}
문제 3---일반 메서드 추가 시, 메시지 전송 후에 hello가 출력될까요?
public class B {
public static void main(String[] args) throws InterruptedException {
Phone2 phone = new Phone2();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone.hello(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
class Phone2 {
// synchronized는 메서드 호출자에 대한 락
// 두 메서드는 동일한 락 사용, 먼저 획득한 스레드가 실행
public synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
public synchronized void makeCall() {
System.out.println("전화 걸기");
}
// 락이 없음, 동기화 메서드가 아님
public void hello() {
System.out.println("hello");
}
}
문제 4---다른 객체로 메시지 전송과 hello 메서드 호출 시 결과는?
public class B {
public static void main(String[] args) throws InterruptedException {
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
try {
phone1.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone2.hello(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
class Phone2 {
public synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
public synchronized void makeCall() {
System.out.println("전화 걸기");
}
// 락이 없음, 동기화 메서드가 아님
public void hello() {
System.out.println("hello");
}
}
설명은 동일합니다
문제5---static 키워드 추가 시 실행 결과는?
public class C {
public static void main(String[] args) throws InterruptedException {
Phone3 phone = new Phone3();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone.makeCall(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
// Phone3은 유일한 클래스 객체 Phone3.class(전역 유일)
class Phone3 {
// synchronized는 메서드 호출자에 대한 락
// 두 메서드는 동일한 락 사용, 먼저 획득한 스레드가 실행
// static 메서드는 클래스 로딩 시 생성, 클래스 템플릿
// 이 경우 락은 클래스 객체
public static synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
public static synchronized void makeCall() {
System.out.println("전화 걸기");
}
}
문제6---static 키워드로 수정한 후 두 개의 다른 객체로 호출 시 결과는?
public class C {
public static void main(String[] args) throws InterruptedException {
// 두 객체지만, 현재 락은 클래스 객체
// 두 객체의 클래스 템플릿은 하나만 존재
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{
try {
phone1.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone2.makeCall(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
// Phone3은 유일한 클래스 객체 Phone3.class(전역 유일)
class Phone3 {
// synchronized는 메서드 호출자에 대한 락
// 두 메서드는 동일한 락 사용, 먼저 획득한 스레드가 실행
// static 메서드는 클래스 로딩 시 생성, 클래스 템플릿
// 이 경우 락은 클래스 객체
public static synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
public static synchronized void makeCall() {
System.out.println("전화 걸기");
}
}
문제7--일반 동기화 메서드와 정적 동기화 메서드 함께 사용 시 실행 순서는?
public class D {
public static void main(String[] args) throws InterruptedException {
Phone4 phone = new Phone4();
new Thread(()->{
try {
phone.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone.makeCall(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
// Phone4은 유일한 클래스 객체 Phone4.class(전역 유일)
class Phone4 {
// 정적 동기화 메서드
public static synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
// 일반 동기화 메서드
public synchronized void makeCall() {
System.out.println("전화 걸기");
}
}
분석:
문제8: 두 개의 다른 객체로 호출 시 결과는?
public class D {
public static void main(String[] args) throws InterruptedException {
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(()->{
try {
phone1.sendMessage();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"ThreadA").start();
// 1초 대기
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone2.makeCall(); },"ThreadB").start();
}
}
@SuppressWarnings("all")
// Phone4은 유일한 클래스 객체 Phone4.class(전역 유일)
class Phone4 {
// 정적 동기화 메서드
public static synchronized void sendMessage() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("메시지 전송");
}
// 일반 동기화 메서드
public synchronized void makeCall() {
System.out.println("전화 걸기");
}
}
결과: