2017-03-30-多线程
Xplorist Lv6

2017-03-30-多线程

知识点1:

线程:

单核cpu实际串行运行,线程交替执行,可以看做是并行。

知识点2:

创建线程实际上只有一种方法,只有线程才能够创建线程,继承实现和接口实现区别不大,都是对run()方法的重写。

具体的线程的功能还是线程类提供的。

继承实现和接口实现的区别:

同样都是通过实现Thread类来实现。

继承是将这个类变成了Thread的一部分,创建线程就是直接创建这个类的对象,每个对象的run()方法都是对象的所独有的。

接口只是将这个类实现了run()方法的重写,多个线程可以调用一个实现类的对象进行线程运行,运行的是一个类的同一个对象中的同一个方法,这一点是继承的方式所不能实现的,真的很神奇。

知识点3:

异常只会中断线程,而不会使整个程序崩溃。

主线程和子线程区别不是很大。

思考题1:

2017-03-30-01.png

答案:t.start()与t.run()结果不一样,start是将run方法中的流程放进cpu调度中,run是直接运行run方法。

思考题2:
2017-03-30-02.png

答案:还会获得调度

图文详解:

获取当前线程对象:
2017-03-30-03.png


两个线程交替睡眠交替执行流程图:
2017-03-30-04.png


游戏计时系统:
2017-03-30-05.png
2017-03-30-06.png


合并线程:
2017-03-30-07.png
2017-03-30-08.png


线程与异常:

异常并不会终止整个程序的运行,只会终止这个线程
2017-03-30-09.png

实例1:

使用两种方式创建线程:1.使用继承,2.实现接口

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.share.demo03_30_多线程;

public class ThreadTest extends Thread{
    public String name;
    
    public ThreadTest(String name) {
        super(name);
        this.name=name;
    }


    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println(name+"T+++++++++"+i);
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.share.demo03_30_多线程;

public class ThreadTest01 implements Runnable {
    public String name;
    
    public ThreadTest01(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println(name+"T1-------------------------"+i);
        }
    }
    
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.share.demo03_30_多线程;

public class ThreadTest02 implements Runnable {
    public String name;
    
    public ThreadTest02(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<1000;i++){
            System.out.println(name+"T2******************"+i);
        }
    }
    
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.share.demo03_30_多线程;

public class Test {
    public static void main(String[] args) {
        ThreadTest t=new ThreadTest("线程T0");
        Thread t1=new Thread(new ThreadTest01("线程T1"));
        Thread t2=new Thread(new ThreadTest02("线程T2"));
        
        t.setPriority(10);
        t1.setPriority(5);
        t2.setPriority(1);
        
        t.start();
        t1.start();
        t2.start();
        
        
    }
}

实例2:

创建一个游戏时间的线程,创建一个北京时间的线程,

在主线程中实现两个线程交替执行

思路:

线程休眠

核心代码:

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
package com.share.demo03_30_多线程;

import java.text.SimpleDateFormat;
import java.util.Date;

public class GameTime implements Runnable {
    public Date date;
    public long d;

    @Override
    public void run() {
        d = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        while (true) {
            date = new Date(d);
            String time = sdf.format(date);

            System.out.println("游戏时间:" + time);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            d += 1000 * 60 * 60;
        }
    }

}

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
package com.share.demo03_30_多线程;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test01 {
    public static void main(String[] args) {
        Thread t=new Thread(new GameTime());
        Thread t1=Thread.currentThread();
        t1.stop();
        t.stop();
        t.start();
        int count=0;
        //t.run();
        while(true){
            Date date=new Date();
            SimpleDateFormat sdf=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
            String time=sdf.format(date);
            
            try {
                System.out.println("北京时间:"+time);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(count==10){
                //t1.stop();
            }
            count++;
        }
    }
}

实例3:
2017-03-30-10.png

思路:

线程的合并

核心代码:

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
package com.share.demo03_30_多线程;

import java.io.File;
import java.util.Scanner;

public class TestJoin {
    class ChildJoinThread implements Runnable {

        @Override
        public void run() {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入名称:");
            String s = sc.next();
            System.out.println("名称:" + s);
        }

    }

    public static void main(String[] args) {
        Thread t = new Thread(new TestJoin().new ChildJoinThread(), "子线程");

        File file = new File("C:\\Users\\Administrator\\Desktop");
        File[] fa = file.listFiles();
        int count = 0;
        for (File f : fa) {
            count++;
            if (count == 5) {
                t.start();
                try {
                    t.join();
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
            System.out.println(f.getName());

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

实例4:
2017-03-30-11.png

思路:

核心代码:

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
package com.share.demo03_30_多线程;

public class VirtualTicketSellSystem  {
    public static int num=100;
    public static void main(String[] args) {
        VirtualTicketSellSystem vtss=new VirtualTicketSellSystem();
        Thread t1=new Thread(vtss.new SellWindows("1"),"子线程1");
        Thread t2=new Thread(vtss.new SellWindows("2"),"子线程2");
        Thread t3=new Thread(vtss.new SellWindows("3"),"子线程3");
        t1.start();
        t2.start();
        t3.start();
    }
    
    class SellWindows implements Runnable{
        public String name;
        
        public SellWindows(String name) {
            super();
            this.name = name;
        }

        @Override
        public void run() {
            while(num>0){
                System.out.println("窗口"+name+" 车票ID:"+(num));
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                num--;
            }
        }
        
    }
}

这种方法并不能保证每张车票只能被买一次,因为多线程来访问,有可能同时改变数据


老师的思路:

2017-03-30-12.png

实例5:
2017-03-30-13.png

思路:

1.用数字模拟时间

2.用实际的时间来做

重要判定:

时间结束,题目做完都是考试结束的判断标志,自己没有考虑到题目做完的情况,是逻辑不够严密的,虽然感觉很重要,逻辑理性思维还是很重要。

思路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
package com.share.demo03_30_多线程;

public class VirtualTest {
    public static void main(String[] args) {
        VirtualTest vt = new VirtualTest();
        Thread t1 = new Thread(vt.new Student("学生1"), "线程1");
        Thread t2 = new Thread(vt.new Student("学生2"), "线程2");
        Thread t3 = new Thread(vt.new Student("学生3"), "线程3");
        t1.start();
        t2.start();
        t3.start();
    }

    //
    class Student implements Runnable {
        public String name;

        public Student(String name) {
            this.name = name;
        }

        public int time = 60;
        public int testMount = 30;

        @Override
        public void run() {
            int testLeft = 30;
            
            for (int i = 1; i <= 30; i++) {
                int currentUsedTime=(int)(Math.random()*4+1);
                System.out.println(name+"做第"+i+"题花了"+currentUsedTime+"秒");
                time-=currentUsedTime;
                if(time<0){
                    System.out.println(name+"考试时间到了,做到了第"+i+"题,但是这道题没有完成");
                    testLeft-=--i;
                    break;
                }else if(time==0){
                    System.out.println(name+"考试时间到了,做到了第"+i+"题,这道题完成了");
                    testLeft-=i;
                    break;
                }
            }
            System.out.println(name+"最后剩下了"+testLeft+"完成了"+(30-testLeft)+"道题,完成度:"+(((30-testLeft)/30.0)*100)+"%");
        }
    }

}

思路2核心代码:

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
package com.share.demo03_30_多线程;

/**
 * 通过真实的时间来做,真的时间过一秒,不一定能够完成一道题,用一个数组将每道题的难度随机出来,<br>
 * 过完一秒,比较这个题剩下的进度,如果这个时间和难度相同了,就进入到下一个题目中,就进入到数组中的下一个元素,数组的下标就加1<br>
 * 
 * 
 * @author brx
 */
public class VirtualExamination {
    public static void main(String[] args) {
        class Student extends Thread {

            public Student(String name) {
                super(name);
            }

            @Override
            public void run() {

                int[] d = new int[30];
                for (int i = 0; i < d.length; i++) {
                    d[i] = (int) (Math.random() * 4 + 1);
                }
                int count = 0;
                int num = 0;
                int n = 0;

                while (count < 60) {
                    count++;
                    System.out.println(getName() + "第" + count + "秒");
                    n++;
                    System.out.println(getName() + "第" + (num + 1) + "个题的难度为:" + d[num]);
                    if (d[num] == n) {
                        num++;
                        n = 0;
                        System.out.println(getName() + "【完成了】第" + (num) + "题");
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
                System.out.println("【" + getName() + "】【总共完成做了】" + num + "个题,完成度:" + ((num / 30.0) * 100) + "%");

            }
        }
        Student s1 = new Student("学生1");
        Student s2 = new Student("学生2");
        Student s3 = new Student("学生3");
        s1.start();
        s2.start();
        s3.start();

    }
}

老师的思路:通过主线程控制时间,支线程只负责做题。

老师的思路的核心代码:

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
package com.share.test_3_31;

import java.util.Random;

public class ZuoYe1 {

    /*
     * 模拟考试。。考试时间60秒 有4个考生,试卷有30道题,考生的做题速度随机1-4秒做一道题
     * 考试开始时,考生开始做题,考试时间到之后收卷,所有考生不能再答题 输出每一个考生的答题情况,例如:考生1:在规定时间完成了15题,完成度:50%
     */

    public static int time = 100;// 时间轴
    public static boolean bool = true;// 允许答题

    public class Student extends Thread {
        public Student(String name) {
            super(name);
        }
        @Override
        public void run() {
            int n = 0;
            while (n < 30 && bool) {
                n++;
                try {
                    Thread.sleep((new Random().nextInt(4) + 1) * time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (!bool) {
                System.out.println(
                        "时间到," + Thread.currentThread().getName() + "完成了 " + n + " 道题,完成度:" + n * 100 / 30.0 + "%");
            } else {
                System.out.println(Thread.currentThread().getName() + "提前完成了考试");
            }
        }
    }

    public static void main(String[] args) {

        Student s1 = new ZuoYe1().new Student("1号考生");
        Student s2 = new ZuoYe1().new Student("2号考生");
        Student s3 = new ZuoYe1().new Student("3号考生");
        Student s4 = new ZuoYe1().new Student("4号考生");
        System.out.println("考试开始:");
        s1.start();
        s2.start();
        s3.start();
        s4.start();
        try {
            Thread.sleep(60 * time); // 考试时间60秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 考试结束,收卷,判断结果
        bool = false;

    }

}

源码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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package com.share.demo03_30_多线程;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Vector;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ChatClientFrame extends JFrame {
    private JTextField tf_newUser;
    private JList user_list;
    private JTextArea ta_info;
    private JTextField tf_send;
    private ObjectOutputStream out;// 声明输出流对象
    private boolean loginFlag = false;// 为true时表示已经登录,为false时表示未登录
    
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ChatClientFrame frame = new ChatClientFrame();
                    frame.setVisible(true);
                    frame.createClientSocket();// 调用方法创建套接字对象
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    public void createClientSocket() {
        try {
            Socket socket = new Socket("172.18.6.3", 8082);// 创建套接字对象
            out = new ObjectOutputStream(socket.getOutputStream());// 创建输出流对象
            new ClientThread(socket).start();// 创建并启动线程对象
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    class ClientThread extends Thread {
        Socket socket;
        public ClientThread(Socket socket) {
            this.socket = socket;
        }
        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));// 创建输入流对象
                DefaultComboBoxModel model = (DefaultComboBoxModel) user_list
                        .getModel();// 获得列表框的模型
                while (true) {
                    String info = in.readLine().trim();// 读取信息
                    if (!info.startsWith("MSG:")) {// 接收到的不是消息
                        if (info.startsWith("退出:")) {// 接收到的是退出消息
                            model.removeElement(info.substring(3));// 从用户列表中移除用户
                        } else {// 接收到的是登录用户
                            boolean itemFlag = false;// 标记是否为列表框添加列表项,为true不添加,为false添加
                            for (int i = 0; i < model.getSize(); i++) {// 对用户列表进行遍历
                                if (info.equals((String) model.getElementAt(i))) {// 如果用户列表中存在该用户名
                                    itemFlag = true;// 设置为true,表示不添加到用户列表
                                    break;// 结束for循环
                                }
                            }
                            if (!itemFlag) {
                                    model.addElement(info);// 将登录用户添加到用户列表
                            } 
                        }
                    } else {// 如果获得的是消息,则在文本域中显示接收到的消息
                        DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例
                        String dateString = df.format(new Date());         // 格式化为日期
                        df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例
                        String timeString = df.format(new Date());         // 格式化为时间
                        String sendUser = info.substring(4,info.indexOf(":发送给:"));// 获得发送信息的用户
                        String receiveInfo = info.substring(info.indexOf(":的信息是:")+6);// 获得接收到的信息
                        ta_info.append("  "+sendUser + "    " +dateString+"  "+timeString+"\n  "+receiveInfo+"\n");// 在文本域中显示信息
                        ta_info.setSelectionStart(ta_info.getText().length()-1);// 设置选择起始位置
                        ta_info.setSelectionEnd(ta_info.getText().length());// 设置选择的结束位置
                        tf_send.requestFocus();// 使发送信息文本框获得焦点
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    private void send() {
        if (!loginFlag) {
            JOptionPane.showMessageDialog(null, "请先登录。");
            return;// 如果用户没登录则返回
        }
        String sendUserName = tf_newUser.getText().trim();// 获得登录用户名
        String info = tf_send.getText();// 获得输入的发送信息
        if (info.equals("")) {
            return;// 如果没输入信息则返回,即不发送
        }
        Vector<String> v = new Vector<String>();// 创建向量对象,用于存储发送的消息
        Object[] receiveUserNames = user_list.getSelectedValues();// 获得选择的用户数组
        if (receiveUserNames.length <= 0) {
            return;// 如果没选择用户则返回
        }
        for (int i = 0; i < receiveUserNames.length; i++) {
            String msg = sendUserName + ":发送给:" + (String) receiveUserNames[i]
                    + ":的信息是: " + info;// 定义发送的信息
            v.add(msg);// 将信息添加到向量
        }
        try {
            out.writeObject(v);// 将向量写入输出流,完成信息的发送
            out.flush();// 刷新输出缓冲区
        } catch (IOException e) {
            e.printStackTrace();
        }
        DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例
        String dateString = df.format(new Date());         // 格式化为日期
        df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例
        String timeString = df.format(new Date());         // 格式化为时间
        String sendUser = tf_newUser.getText().trim();// 获得发送信息的用户
        String receiveInfo = tf_send.getText().trim();// 显示发送的信息
        ta_info.append("  "+sendUser + "    " +dateString+"  "+timeString+"\n  "+receiveInfo+"\n");// 在文本域中显示信息
        tf_send.setText(null);// 清空文本框
        ta_info.setSelectionStart(ta_info.getText().length()-1);// 设置选择的起始位置
        ta_info.setSelectionEnd(ta_info.getText().length());// 设置选择的结束位置
        tf_send.requestFocus();// 使发送信息文本框获得焦点
    }
    
    /**
     * Create the frame
     */
    public ChatClientFrame() {
        super();
        setTitle("聊天室客户端");
        setBounds(100, 100, 385, 288);
        
        final JPanel panel = new JPanel();
        getContentPane().add(panel, BorderLayout.SOUTH);
        
        final JLabel label = new JLabel();
        label.setText("输入聊天内容:");
        panel.add(label);
        
        tf_send = new JTextField();
        tf_send.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 调用方法发送信息
            }
        });
        tf_send.setPreferredSize(new Dimension(180, 25));
        panel.add(tf_send);
        
        final JButton button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 调用方法发送信息
            }
        });
        button.setText("发  送");
        panel.add(button);
        
        final JSplitPane splitPane = new JSplitPane();
        splitPane.setDividerLocation(100);
        getContentPane().add(splitPane, BorderLayout.CENTER);
        
        final JScrollPane scrollPane = new JScrollPane();
        splitPane.setRightComponent(scrollPane);
        
        ta_info = new JTextArea();
        ta_info.setFont(new Font("", Font.BOLD, 14));
        scrollPane.setViewportView(ta_info);
        
        final JScrollPane scrollPane_1 = new JScrollPane();
        splitPane.setLeftComponent(scrollPane_1);
        
        user_list = new JList();
        user_list.setModel(new DefaultComboBoxModel(new String[] { "" }));
        scrollPane_1.setViewportView(user_list);
        
        final JPanel panel_1 = new JPanel();
        getContentPane().add(panel_1, BorderLayout.NORTH);
        
        final JLabel label_1 = new JLabel();
        label_1.setText("用户名称:");
        panel_1.add(label_1);
        
        tf_newUser = new JTextField();
        tf_newUser.setPreferredSize(new Dimension(140, 25));
        panel_1.add(tf_newUser);
        
        final JButton button_1 = new JButton();
        button_1.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (loginFlag) {// 已登录标记为true
                    JOptionPane.showMessageDialog(null, "在同一窗口只能登录一次。");
                    return;
                }
                String userName = tf_newUser.getText().trim();// 获得登录用户名
                Vector v = new Vector();// 定义向量,用于存储登录用户
                v.add("用户:" + userName);// 添加登录用户
                try {
                    out.writeObject(v);// 将用户向量发送到服务器
                    out.flush();// 刷新输出缓冲区
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                tf_newUser.setEnabled(false);// 禁用用户文本框
                loginFlag = true;// 将已登录标记设置为true
            }
        });
        button_1.setText("登  录");
        panel_1.add(button_1);

        final JButton button_2 = new JButton();
        button_2.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                String exitUser = tf_newUser.getText().trim();
                Vector v = new Vector();
                v.add("退出:" + exitUser);
                try {
                    out.writeObject(v);
                    out.flush();// 刷新输出缓冲区
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                System.exit(0);                                     // 退出系统
            }
        });
        button_2.setText("退  出");
        panel_1.add(button_2);
        //托盘
        if (SystemTray.isSupported()){                                      // 判断是否支持系统托盘
            URL url=ChatClientFrame.class.getResource("client.png");          // 获取图片所在的URL
            ImageIcon icon = new ImageIcon(url);                            // 实例化图像对象
            Image image=icon.getImage();                                    // 获得Image对象
            TrayIcon trayIcon=new TrayIcon(image);                          // 创建托盘图标
            trayIcon.addMouseListener(new MouseAdapter(){                   // 为托盘添加鼠标适配器
                public void mouseClicked(MouseEvent e){                     // 鼠标事件
                    if (e.getClickCount()==2){                              // 判断是否双击了鼠标
                        showFrame();                                    // 调用方法显示窗体
                    }
                }
            });
            trayIcon.setToolTip("系统托盘");                                    // 添加工具提示文本
            PopupMenu popupMenu=new PopupMenu();                    // 创建弹出菜单
            MenuItem exit=new MenuItem("退出");                           // 创建菜单项
            exit.addActionListener(new ActionListener() {                   // 添加事件监听器
                public void actionPerformed(final ActionEvent arg0) {
                    String exitUser = tf_newUser.getText().trim();
                    Vector v = new Vector();
                    v.add("退出:" + exitUser);
                    try {
                        out.writeObject(v);
                        out.flush();// 刷新输出缓冲区
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    System.exit(0);                                     // 退出系统
                }
            });
            popupMenu.add(exit);                                        // 为弹出菜单添加菜单项
            trayIcon.setPopupMenu(popupMenu);                           // 为托盘图标加弹出菜弹
            SystemTray systemTray=SystemTray.getSystemTray();           // 获得系统托盘对象
            try{
                systemTray.add(trayIcon);                               // 为系统托盘加托盘图标
            }catch(Exception e){
                e.printStackTrace();
            }
        }

    }
    public void showFrame(){
        this.setVisible(true);                                              // 显示窗体
        this.setState(Frame.NORMAL);
    }

}
 评论