2017-03-30-多线程
知识点1:
线程:
单核cpu实际串行运行,线程交替执行,可以看做是并行。
知识点2:
创建线程实际上只有一种方法,只有线程才能够创建线程,继承实现和接口实现区别不大,都是对run()方法的重写。
具体的线程的功能还是线程类提供的。
继承实现和接口实现的区别:
同样都是通过实现Thread类来实现。
继承是将这个类变成了Thread的一部分,创建线程就是直接创建这个类的对象,每个对象的run()方法都是对象的所独有的。
接口只是将这个类实现了run()方法的重写,多个线程可以调用一个实现类的对象进行线程运行,运行的是一个类的同一个对象中的同一个方法,这一点是继承的方式所不能实现的,真的很神奇。
知识点3:
异常只会中断线程,而不会使整个程序崩溃。
主线程和子线程区别不是很大。
思考题1:
答案:t.start()与t.run()结果不一样,start是将run方法中的流程放进cpu调度中,run是直接运行run方法。
思考题2:
答案:还会获得调度
图文详解:
获取当前线程对象:
两个线程交替睡眠交替执行流程图:
游戏计时系统:
合并线程:
线程与异常:
异常并不会终止整个程序的运行,只会终止这个线程
实例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() { 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) { 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; 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) { e.printStackTrace(); } if(count==10){ } count++; } } }
|
实例3:
思路:
线程的合并
核心代码:
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) { e1.printStackTrace(); } } System.out.println(f.getName());
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
实例4:
思路:
核心代码:
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) { e.printStackTrace(); } num--; } } } }
|
这种方法并不能保证每张车票只能被买一次,因为多线程来访问,有可能同时改变数据
老师的思路:
实例5:
思路:
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_多线程;
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) { 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 {
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); } 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; 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; for (int i = 0; i < model.getSize(); i++) { if (info.equals((String) model.getElementAt(i))) { itemFlag = true; break; } } if (!itemFlag) { model.addElement(info); } } } else { DateFormat df = DateFormat.getDateInstance(); String dateString = df.format(new Date()); df = DateFormat.getTimeInstance(DateFormat.MEDIUM); 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(); String dateString = df.format(new Date()); df = DateFormat.getTimeInstance(DateFormat.MEDIUM); 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(); }
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) { 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; } }); 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"); ImageIcon icon = new ImageIcon(url); Image image=icon.getImage(); 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); }
}
|