마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

안드로이드 while문을 돌리면 쓰레드가 파업해버립니다..

0 추천
     Thread th = new Thread(new Runnable() {
                    @Override
                    public void run() {   // 서버로부터 계속해서 메시지 받기 대기.
                        try {
                            while (true) {
                                Object obj = ois.readObject();
                                if(obj.getClass().getName().equals("com.example.user.carpool_client.SendObject")){
                                    so = (SendObject)obj;
                                    System.out.println("서버로 부터 받은 메시지 : " + so.msg);
                                    new Client_Protocol(so.msg);
                                }else if(obj.getClass().getName().equals("java.util.Vector")){
                                    Vector<MakeInfo> vc_MakeInfo = (Vector<MakeInfo>)obj;
                                    helper h = new helper();
                                    h.arriveVector = true;
//                                    for(int i=0;0<vc_MakeInfo.size();i++){
//                                        h.Static_Request_MakeInfo.add(vc_MakeInfo.elementAt(i));
//                                }
                                    System.out.println("벡터 초기화");
//                                    Progress_Handler.sendEmptyMessage(1);
                                }
                            }
                        } catch (ClassCastException e) {
                            e.printStackTrace();
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        } catch (EOFException e) {
                            e.printStackTrace();
                        } catch (SocketException e) {
                            try {
                                oos.close();
                                ois.close();
                                socket.close();
                            } catch (IOException e1) {
                                e1.printStackTrace();
                            }
                        } catch (IOException e) {
                            try {
                                oos.close();
                                ois.close();
                                socket.close();
                                e.printStackTrace();
                            } catch (IOException e1) {
                                e1.printStackTrace();
                            }

                        }
                    }
                });
                th.start();
   public class Client_Protocol {


        StringTokenizer token = null;

        Client_Protocol(String msg) {
            String fp = "";//First Protocol
            String n_message = "";//next Protocol message

            token = new StringTokenizer(msg, "/");
            fp = token.nextToken();
            n_message = token.nextToken();
            if (fp.equals("LOGINPAGE")) {
                Login_protocol(n_message);
            } else if (fp.equals("CREATEPAGE")) {
                Id_Check(n_message);
            }
        }//Protocol Constructor end
//        Client_Protocol(Vector<MakeInfo> vc_MakeInfo){
//            helper h = new helper();
//            h.Static_Request_MakeInfo = vc_MakeInfo;
//            arriveVector = true;
//            System.out.println("벡터 초기화");
//        }

        private void Login_protocol(String m) {
            token = new StringTokenizer(m, "@");
            String protocol = token.nextToken();
            String msg = token.nextToken();

            if (protocol.equals("ISRIGHT") && msg.equals("true")) {//Carpool main 점 시작.
                intent = new Intent(getApplicationContext(), Carpool_main_Activity.class);
                so.msg = "REQUEST_INFO/" + editText_id.getText().toString();
                send_toServer(so); //사용자의 정보를 얻어옵니다.

            } else if (protocol.equals("ISRIGHT") && msg.equals("false")) {
                println("계정 정보가 틀렸습니다.");
            } else if (protocol.equals("ISRIGHT") && msg.equals("notfound")) {
                println("아이디가 틀렸습니다.");
            } else if (protocol.equals("LOGIN")) {
                intent.putExtra("SendObject",so);
                SharedPreferences pref = getSharedPreferences("pref", 0);
                SharedPreferences.Editor editor = pref.edit();
                editor.putString("ID",so.id);
                editor.commit();

                send_toServer("REQUEST_ROOM_INFO/NO_MEANING");

                Progress_Handler.sendEmptyMessage(0);
                while(true){
                    if(!helper.arriveVector){
//                        System.out.println("while 도는중");
                    }else{
                        Progress_Handler.sendEmptyMessage(1);
                        break;
                    }
                }
                System.out.println("액티비티 실행");
            }
        }//Login_protocol end


        private void Id_Check(String m) {
            if (m.equals("EXIT")) {
                helper.g_msg = m;
                System.out.println(" GLobal Mesaage change");
            } else {
                helper.g_msg = m;
                System.out.println(" GLobal Mesaage change");
            }

        }

    }

 

 

 

첫번째 코드에서 readobject를 받아오는데, 제가 두번째 코드에서 while문을 걸어버리면 readobject받아오는 녀석이 파업하고 서버에서 보내도 받아오질 않네요 .. 한달째 보고있는데 도대체 왜이러는걸까요??

 

일단 저걸 하는 이유는 processdialog를 띄우는동안에 메인을 멈춰놓고 저 쓰레드에서 데이터를 받아오면 그때부터 실행하게끔 하고싶은데.. 도저희 방법을 모르겠네요..

아 그리고 에러는 발생하지않았습니다.

gsm2055 (260 포인트) 님이 2016년 8월 29일 질문

1개의 답변

+1 추천
Client_Protocol 이라는 인스턴스 안에 있는 while 루프때문에 block이 걸려서 두번째 readObject는 동작하지 않을것입니다. Client_Protocol 안에 있는 while루프 구간도 thread 안에서 돌리시던가 해야지 그 다음 readObject가 정상 동작 합니다.

통신 프로그램에서 시작시점이 되는 read 함수 구간에는 최대한 block이 걸리면 안됩니다.

 

그리고 이건 참고 하셨으면 해서 적어 드리는데 굳이 object단위로 송수신 하시는 이유가 있으신가요? 사용하는데 간편하긴 하지만 object 자체의 사이즈가 작으면 상관 없긴한데 object 사이즈가 커지면 문제가 발생할 수 있습니다.

이때 들어오는 바이너리 데이터를 핸들링 하여야할 경우가 생기는데 저렇게 object로 묶어서 던지고 받게 해놓으면 그런 것을 할 수가 없게 됩니다.
Development Guy (70,570 포인트) 님이 2016년 8월 30일 답변
질문 답변에 감사드립니다.
우선 object단위로 하는이유는 이게 제 첫번째 자바 프로그래밍이라 보면서 하다보니까 Object를 쓰더군요.. 그래서 Object를 맨처음에 썻는데 String 형만 주다가 나중에 직렬화를 하다보니 Data통신으로 굳이 바꾸지 않아도 String형과 Object형모두 쓸수 있게되서 Object로 쓰고있습니다. inputData로 두가지 스트림을 연결해버릴수 있는지는 잘 모르겠습니다..

질문자님께서 말씀해주신데로 Object데이터양이 만아지게되면 문제가 생길것이라 생각해서 최대한 적은 Object양만을 보내게끔 하고 있습니다. 단순한 String형이라던지 직렬화에서도 데이터 양을 줄이게끔요.

말씀해주신 바이너리 데이터를 핸들링하는경우가 지금 제수준에서는 없을거같아 일단은 무리가 없지 않을까싶습니다만 지식 수준이 짧아 질문자님의 답변을 정확히 이해하지 못한게 더 크네요 ㅠ.ㅠ

제가 알고 있는 지식으로는 프로세스에서 쓰레드는 파생되어 나오게 되는데,

Client_Protocol는 일반 클래스로 프로세스에서 실행되어지고 readobject는 쓰레드로 하는데 도대체 왜 파업을 하게 되는것인가요??

프로세스에서 while을 실행한다 하여도 readobject는 thread이기에 별개로 작동해야 하지 않나요??

질문자님이 말씀하신대로 Thread를 Client_Protocol에서 while을 실행한다면
class에서 실행되는 문장과 Thread에서 실행되는 while이 별개로 독립적으로 되는것이 아닌지요??

Thread부분도 책을 여러번 읽어보고 구글링도 만이해봤는데 도저희 이해가 안되네요.. join을 이용해서 쓰레드가 기다리게끔 만들어보려고 했는데 join도 안먹어버리더군요.. 그냥 Clinet_Protocol이 독립적으로 Thread와 움직여서 먼저 액티비티를 실행해버립니다.
개념을 잘못 이해하고 계신거 같은데
쓰레드도 프로세스의 일부이고 쓰레드의 부모가되는 프로세스의 리소스중 일부를 사용합니다.

쓰레드라고 해서 프로세스와 독립적으로 동작하는것이 아니에요. 비동기로 동작하기때문에 별개로 보일 뿐이지요.

시스템 프로그래밍 하실때 fork 같은 개념으로 착각 하고 계신거 같은데 fork는 부모 프로세스가 자식 프로세스를 낳는 방식이기 때문에 작성자님이 말하시는 개념이 맞지만 안드로이드 3rd party 어플리케이션에서는 시스템 권한이 제한되어 있습니다. 따라서 이 방식은 사용할 수가 없습니다.

결과적으로 Client_Protocol 인스턴스 생성자 자체가 지금 쓰레드 안에서 무한 while문을 타고 있는데 위에 코드처럼 하는거랑 쉽게 말해서 new 로 인스턴스 초기화를 안시키고 특정 함수를 사용하거나 아니면 Login_Protocol 함수에 있는 while 루프를 하드코딩 한거나 같은 결과 입니다.

질문자님께서 "일반 클래스로 프로세스에서 실행되어지고" 라고 이의를 제기하시는 부분이 어떻게 알고 계셔서 하시는 말씀인지는 모르겠으나 일단 인스턴스 초기화가 쓰레드 내부이건 외부이건 이거는 위의 문제와 아무 상관 없는 부분입니다.

절대로 쓰레드 안에서 new로 인스턴스를 생성하였다고 하여서 그 쓰레드로부터 독립적으로 동작하는 개념이 아닙니다. 이문제는 단순히 new 키워드를 쓰는 순간 생성자가 동작 하고 지금 그 생성자 부분에서 readObject를 수행하지 못하도록 막고 있는 문제인 것입니다.
아.. 제가 Thread안에서 인스턴스를 생성해서 이게 쓰레드에 종속이 되어버렸던 문제였군요 ㅠㅠ 너무도 당연한걸가지고 한달동안 생각했네요...
정말 감사합니다!

쓰레드 부분에 관해서는 단순히 자바 입문용 책만 보고 배운것이라 os에 관련된 지식도 없고 해서 좀더 파봐야할 것 같습니다. 좋은말씀 너무너무 감사합니다.
...