컴퓨터 관련/JAVA 강의

java #31 Thread, 채팅프로그램, static import

승명 2016. 12. 18. 20:48

java #31 Thread, 채팅프로그램, static import

 
* Thread

정의

- 작은 Process(프로세스의 조각 한 개) : CPU가 한번에 처리하는 일(사용자가 실행시킨 프로그램)의 단위
- CPU의 가용성을 높이기 위해 프로세스를 잘게 쪼개서 스케줄에 의해 처리함.
- 동시에 코드를 실행할때 (동시에 일처리할때)
- Multi Thread 지원
- 선점형 cpu 스케줄링 (작업관리자가 없다. 우선순위를 변경할 수 있다.)

사용법

- Thread를 상속하거나 Runnable을 구현하여 사용함

구현법

Thread 상속
Runnable 인터페이스 구현
//다른 클래스를 상속하며 동시에 인터페이스를 구현하여 
Thread를 할 수 있어서 더 많이 씀.
1. Thread class를 상속
1
public class Test extends Thread{
cs

2. run method override
1
2
3
public void run(){
// 동시에 처리될 코드
}
cs

3. start method 호출
1
2
Test t = new Test(); //  자식클래스 객체화
t.start();
cs

Object :
wait(), notify(), notifyAll()
Thread:
Start(), run(), sleep()
Test

1. Runnable 인터페이스 
1
  public class Test implements Runnable{
cs

2. run method override  
1
public void run(){   // 동시에 처리할 코드
cs

Object
Runnable
run()



Test
run()





Thread
start()
run()

runnable

3. start를 호출. Thread로 처리
- Thread 생성
1
2
3
4
5
6
Thread t = new Thread;
t.start(); // Test.run()이 아닌 Thread.run()을 호출하게 됨. 
            //그러므로 Thread 클래스와 현재클래스를 has a 관계로 설정해야 함.
Thread th = new Thread(t);
th.start();//start 호출
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package day0313;
 
/**
* 동시에 코드를 수행하기 위한 Thread의 사용<br/>
* 상속으로 Thread를 사용하는 방법
*/
//1. Thread를 상속받는다.
public class UseThread extends Thread{
     //2. run method Override 하고
     @Override
     public void run(){
          //Thread로 처리할 코드(동시에 처리되는 코드)
          for(int i=0;i<600;i++){
               System.out.println("run i =======> " +i);              
          }//for
     }//run
     public static void main(String[] args) {
          //3. start() method 호출 Thread로 처리
          UseThread ut=new UseThread();
          ut.start(); // -> Thread가 적용된 run() 호출         
          //ut.run(); //thread로 처리되지 않는다.
          for(int i=0;i<600;i++){
               System.out.println("-----------------main i = "+i);
          }//for
     }//main
}//class
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package day0313;
 
/**
* 동시에 코드를 수행하기 위한 Thread의 사용<br/>
* 구현(implements)으로 Thread를 사용하기
*/
// 1. Runnable interface를 구현
public class UseRunnable implements Runnable {
 
     // 2. run method Override
 
     @Override
     public void run() {
          // 동시에 처리할 코드
          for (int i = 0; i < 600; i++) {
               System.out.println("run i----------->" + i);
          }// for
     }// run
 
     public static void main(String[] args) {
          //객체 생성
          UseRunnable ur = new UseRunnable();
              
          // Thread 객체와 has a 관계 설정
          Thread t=new Thread(ur);
         
          //start()호출
       //t.run();// run method를 직접 호출하면 Thread를 적용받지 못한다.
          t.start();// Thread가 적용된 run() 호출         
          for(int i=0;i<600;i++){
               System.out.println("main i>>>>>>>>>>"+i);              
          }//for         
     }// main
}// class
cs

생명주기

준비상태
↓start(),yeild()
run()
실행(running)
↑Object.notify, Object.notifyAll
↓sleep(), Object.wait()
대기block

↓stop()[실행, 대기로부터]
죽음dead

채팅

* 1:1
채팅프로그램 클라이언트채팅프로그램 서버
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package day0314;
 
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
 
import javax.swing.JOptionPane;
 
/**
* 메세지를 보내고 읽기를 동시에 처리하기 위하여 Thread를 도입하여 클래스를 작성
* 소켓을 사용하여 서버에 연결하고 스트림을 사용하여 서버의 메세지와 나의 메세지를 서버로 전달하는 클래스
*/
@SuppressWarnings("serial")
public class SimpleThreadClient extends Frame implements ActionListener, Runnable {
          
     private TextField tfTalk, tfNick, tfIp;
     private Button btnConnect;
     private TextArea taDisplay;
 
     private Socket client; // 서버에 연결하기 위한 소켓
     private DataInputStream dis; // 메세지를 읽기 위한 스트림
     private DataOutputStream dos; // 메세지를 보내기 위한
 
     public SimpleThreadClient() {
          super("--------------채팅 클라이언트------------------");
          tfTalk = new TextField();
          tfNick = new TextField(10);
          tfIp = new TextField(10);
 
          btnConnect = new Button("접속");
          taDisplay = new TextArea();
          taDisplay.setEditable(false);
          taDisplay.setBackground(Color.WHITE);
 
          Panel panelNorth = new Panel();
 
          panelNorth.add(new Label("서버주소"));
          panelNorth.add(tfIp);
          panelNorth.add(new Label("대화명"));
          panelNorth.add(tfNick);
          panelNorth.add(btnConnect);
 
          add("North", panelNorth);
          add("Center", taDisplay);
 
          add("South", tfTalk);
 
          btnConnect.addActionListener(this);
          tfTalk.addActionListener(this);
 
          setSize(400250);
          setVisible(true);
 
          addWindowListener(new WindowAdapter() {
 
               @Override
               public void windowClosing(WindowEvent e) {
                    dispose();
               }// windowClosing
 
               @Override
               public void windowClosed(WindowEvent e) {
                    try {
                         close();
                    } catch (IOException e1) {
                         e1.printStackTrace();
                    }// catch
               }// windowClosed
          });
 
     }// SimpleClient
 
     private void close() throws IOException {
          if (dis != null) {
               dis.close();
          }// end if
          if (dos != null) {
               dos.close();
          }// end if
          if (client != null) {
               client.close();
          }// end if
     }// close
 
     @Override
     public void run(){
          try{
               if (dis != null) {
                    while (true) {
                         // 데이터(서버의 메세지)를 읽어서 대화창(taDisplay)에 출력
                         taDisplay.append(dis.readUTF() + "\n");
                    }
 
               }// end if
          }catch(IOException ie){
               JOptionPane.showMessageDialog(this"대화상대 접속종료!!!");
          }//end catch
          
          
          
     }//run
     @Override
     public void actionPerformed(ActionEvent ae) {
 
          if (ae.getSource() == btnConnect) {
               String ip=tfIp.getText().replaceAll(" ",""); //공백 없애기
               try {
                    connectToServer(ip);
               } catch (IOException e) {
            JOptionPane.showMessageDialog(this, ip+"에는 서버가 존재하지 않습니다.");
               }//catch
          }// end if
 
          if (ae.getSource() == tfTalk) {
               //대화내용이 입력되면 
               String msg = "["+tfNick.getText()+"]"+tfTalk.getText();
               //텍스트 에어리어에 출력
               taDisplay.append(msg+"\n");
               //서버로 전송
               try {
                    dos.writeUTF(msg); //스트림에 메세지 쓰기
                    dos.flush(); //스트림의 메세지 분출
               } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
               }
               tfTalk.setText("");
          }// end if
     }// actionPerformed
 
     private void connectToServer(String ip) throws IOException {
          if (client == null) {
               // 소켓 생성
               client = new Socket(ip, 3000);
               // 스트림 연결
               dis = new DataInputStream(client.getInputStream());
               dos = new DataOutputStream(client.getOutputStream());
               // 메세지 읽기
 
              //대화상대의 닉네임을 보여주고 채팅참여자가 있다는 것을 대화창에 뿌려준다.
               taDisplay.append("****** "+dis.readUTF()+"님 대화참여\n");
               dos.writeUTF(tfNick.getText());
               dos.flush();
 
               Thread t = new Thread(this);// has a
               t.start(); //run() 호출
          } else {
               JOptionPane.showMessageDialog(this"현재 채팅중입니다.");
 
          }
     }// connectToServer
 
     private void readMsg() throws IOException {
          
     }
 
     public static void main(String[] args) {
          new SimpleThreadClient();
     }// main
 
}// class
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
 
package day0314;
 
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
 
import javax.swing.JOptionPane;
 
/**
* 메세지를 보내고 읽기를 동시에 처리하기 위하여 Thread를 도입하여 클래스를 작성
* 소켓을 사용하여 서버에 연결하고 스트림을 사용하여 서버의 메세지와 나의 메세지를 서버로 전달하는 클래스
*/
@SuppressWarnings("serial")
public class SimpleThreadClient extends Frame implements ActionListener, Runnable {
          
     private TextField tfTalk, tfNick, tfIp;
     private Button btnConnect;
     private TextArea taDisplay;
 
     private Socket client; // 서버에 연결하기 위한 소켓
     private DataInputStream dis; // 메세지를 읽기 위한 스트림
     private DataOutputStream dos; // 메세지를 보내기 위한
 
     public SimpleThreadClient() {
          super("--------------채팅 클라이언트------------------");
          tfTalk = new TextField();
          tfNick = new TextField(10);
          tfIp = new TextField(10);
 
          btnConnect = new Button("접속");
          taDisplay = new TextArea();
          taDisplay.setEditable(false);
          taDisplay.setBackground(Color.WHITE);
 
          Panel panelNorth = new Panel();
 
          panelNorth.add(new Label("서버주소"));
          panelNorth.add(tfIp);
          panelNorth.add(new Label("대화명"));
          panelNorth.add(tfNick);
          panelNorth.add(btnConnect);
 
          add("North", panelNorth);
          add("Center", taDisplay);
 
          add("South", tfTalk);
 
          btnConnect.addActionListener(this);
          tfTalk.addActionListener(this);
 
          setSize(400250);
          setVisible(true);
 
          addWindowListener(new WindowAdapter() {
 
               @Override
               public void windowClosing(WindowEvent e) {
                    dispose();
               }// windowClosing
 
               @Override
               public void windowClosed(WindowEvent e) {
                    try {
                         close();
                    } catch (IOException e1) {
                         e1.printStackTrace();
                    }// catch
               }// windowClosed
          });
 
     }// SimpleClient
 
     private void close() throws IOException {
          if (dis != null) {
               dis.close();
          }// end if
          if (dos != null) {
               dos.close();
          }// end if
          if (client != null) {
               client.close();
          }// end if
     }// close
 
     @Override
     public void run(){
          try{
               if (dis != null) {
                    while (true) {
                         // 데이터(서버의 메세지)를 읽어서 대화창(taDisplay)에 출력
                         taDisplay.append(dis.readUTF() + "\n");
                    }
 
               }// end if
          }catch(IOException ie){
               JOptionPane.showMessageDialog(this"대화상대 접속종료!!!");
          }//end catch
          
          
          
     }//run
     @Override
     public void actionPerformed(ActionEvent ae) {
 
          if (ae.getSource() == btnConnect) {
               String ip=tfIp.getText().replaceAll(" ",""); //공백 없애기
               try {
                    connectToServer(ip);
               } catch (IOException e) {
            JOptionPane.showMessageDialog(this, ip+"에는 서버가 존재하지 않습니다.");
               }//catch
          }// end if
 
          if (ae.getSource() == tfTalk) {
               //대화내용이 입력되면 
               String msg = "["+tfNick.getText()+"]"+tfTalk.getText();
               //텍스트 에어리어에 출력
               taDisplay.append(msg+"\n");
               //서버로 전송
               try {
                    dos.writeUTF(msg); //스트림에 메세지 쓰기
                    dos.flush(); //스트림의 메세지 분출
               } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
               }
               tfTalk.setText("");
          }// end if
     }// actionPerformed
 
     private void connectToServer(String ip) throws IOException {
          if (client == null) {
               // 소켓 생성
               client = new Socket(ip, 3000);
               // 스트림 연결
               dis = new DataInputStream(client.getInputStream());
               dos = new DataOutputStream(client.getOutputStream());
               // 메세지 읽기
 
              //대화상대의 닉네임을 보여주고 채팅참여자가 있다는 것을 대화창에 뿌려준다.
               taDisplay.append("****** "+dis.readUTF()+"님 대화참여\n");
               dos.writeUTF(tfNick.getText());
               dos.flush();
 
               Thread t = new Thread(this);// has a
               t.start(); //run() 호출
          } else {
               JOptionPane.showMessageDialog(this"현재 채팅중입니다.");
          }
     }// connectToServer
 
     private void readMsg() throws IOException {  
     } 
     public static void main(String[] args) {
          new SimpleThreadClient();
     }// main 
}// class
cs


*다:다
서버모든 접속자 소켓 관리, 메세지가 들어오면 모든 접속자에게 뿌린다.
List Arraylist // 리스트에 소켓을 들어오는데로 저장
클라이언트A
클라이언트B
부모Thread()
class Helper
-Socket
-DataInputStream
-DataOutputstream
+static Arraylist(someClient)
+Helper(socket)
들어온 소켓에 스트링 연결
+run(): void
메세지를 읽어서 모든 접속자에게 출력
+broadcast(String):void
-ArrayList에 있는 모든 소켓에 메세지를 출력
class ChatServer
+static main(string []):void
- 서버 소켓을 열고 접속자 소켓이 있다면 Helper에 list 저장 helper를 생성하고 start()호출
* Helper와의 관계 :
for(int i=0; ;i++){
Socket s=server.accept();
Helper h\new Helper(s)
Helper.someClient.add(h);
h.start(0);
}
부모Frame()
인터페이스Runnable()
class ChatClient
+ChatClient();
-connectToServer() : void - 서버와 연결
+run();void - 메세지읽기, TextArea에 출력
+actionPerformed(ActionListener):void:엔터가 쳐졌을때 서버로 메세지 전달
+static main(String[]):void
부모Frame()
인터페이스ActionListener(), Runnable()


* static import
정의
- JDK1.5에서부터 지원하는 문법
- class 내의 static 변수, 메서드를 클래스명 없이 사용하기 위하여
사용법import static 패키지명.클래스명.변수명;
import static 패키지명.클래스명.메서드명;
import static java.util.Calendar.YEAR;  -> YEAR만으로 사용할 수 있음
import static java.lang.Integer.parseInt;  -> parseInt("값");만으로 사용할 수 있음
import static java.lang.Math.abs; -> abs(음수);만으로 사용할 수 있음

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package day0314;
 
/**
* jdk1.5에서부터 지원되는 문법인 static import의 사용
* 다른 클래스의 static 변수, 메서드를 내 클래스에서 클래스명없이 변수, 메서드를 바로 사용하기 위하여
*/
//메소드
import static java.lang.Integer.parseInt;
//변수
import static java.lang.Integer.MAX_VALUE;
import static java.lang.System.out;
public class UseStaticImport {
 
     public static void main(String[] args) {
          String data="2014";ssdf
          //parseInt가 자주 사용된다.
          int i=parseInt(data);
          int j=parseInt(data);
          int k=parseInt(data);
          out.println(i+" "+j+" "+k);
          out.println(MAX_VALUE);
     }//main
}//class