201771010113 李婷华 《面向对象程序设计(Java)》第十六周总结
一.理论知识部分
1.程序是一段静态的代码,它应用程序执行蓝 是一段静态的代码,它应用程序执行蓝 是一段静态的代码,它应用程序执行蓝本。
2.进程是程序的一次动态执行,它对应了从代码加载、执行至执行完毕的一个完整过程。
3.多线程是进程执行过中产生的多条线索。
4.线程是比进程执行更小的单位。
5.线程不能独立存在,必须存在于进程中,同一进 程的各线程间共享进程空间的数据。
6.多线程意味着一个程序的多行语句可以看上去几 乎在同一时间内同时运行。
7.用Thread类的子类创建线程:首先需从Thread类派生出一个子类,在该子类中 重写run()方法。然后用创建该子类的对象。 最后用start()方法启动线程。
8.用Runnable()接口实现线程:首先设计一个实现Runnable接口的类; 然后在类中根据需要重写run方法; 再创建该类对象,以此对象为参数建立Thread 类的对象; 调用Thread类对象的start方法启动线程,将 CPU执行权转交到run方法。
9.线程的终止:当线程的run方法执行方法体中最后一条语句后, 或者出现了在run方法中没有捕获的异常时,线 程将终止,让出CPU使用权。调用interrupt()方法也可终止线程。
10.线程的状态:利用各线程的状态变换,可以控制各个线程轮流 使用CPU,体现多线程的并行性特征。线程有如下7种状态: New (新建) 、Runnable (可运行) 、Running(运行) 、Blocked (被阻塞) 、Waiting (等待) 、Timed waiting (计时等待) 、Terminated (被终止)
11.调用setPriority(int a)重置当前线程的优先级, a 取值可以是前述的三个静态量。
调用getPriority()获得当前线程优先级。
12.多线程并发执行中的问题:
多个线程相对执行的顺序是不确定的。线程执行顺序的不确定性会产生执行结果的不确定性。 在多线程对共享数据操作时常常会产生这种不确定性。
二.实验部分
1、实验目的与要求
(1) 掌握线程概念;
(2) 掌握线程创建的两种技术;
(3) 理解和掌握线程的优先级属性及调度方法;
(4) 掌握线程同步的概念及实现技术;
2、实验内容和步骤
实验1:测试程序并进行代码注释。
测试程序1:
l 在elipse IDE中调试运行ThreadTest,结合程序运行结果理解程序;
l 掌握线程概念;
l 掌握用Thread的扩展类实现线程的方法;
l 利用Runnable接口改造程序,掌握用Runnable接口创建线程的方法。
Thread扩展类:
1 class Lefthand extends Thread { 2 public void run() 3 { 4 for(int i=0;i<=5;i++) 5 { System.out.println("You are Students!"); 6 try{ sleep(500); } 7 catch(InterruptedException e) 8 { System.out.println("Lefthand error.");} 9 } 10 } 11 } 12 class Righthand extends Thread { 13 public void run() 14 { 15 for(int i=0;i<=5;i++) 16 { System.out.println("I am a Teacher!"); 17 try{ sleep(300); } 18 catch(InterruptedException e) 19 { System.out.println("Righthand error.");} 20 } 21 } 22 } 23 public class ThreadTest 24 { 25 static Lefthand left; 26 static Righthand right; 27 public static void main(String[] args) 28 { left=new Lefthand(); 29 right=new Righthand(); 30 left.start(); 31 right.start(); 32 } 33 }
Runnable接口:
1 class Lefthand implements Runnable { 2 public void run() { 3 for (int i = 0; i <= 5; i++) { 4 System.out.println("You are Students!"); 5 try { 6 Thread.sleep(500); 7 } catch (InterruptedException e) { 8 System.out.println("Lefthand error."); 9 } 10 } 11 } 12 } 13 14 class Righthand implements Runnable { 15 public void run() { 16 for (int i = 0; i <= 5; i++) { 17 System.out.println("I am a Teacher!"); 18 try { 19 Thread.sleep(300); 20 } catch (InterruptedException e) { 21 System.out.println("Righthand error."); 22 } 23 } 24 } 25 } 26 27 /*public class TheadTest { 28 static Lefthand left; 29 static Righthand right; 30 31 public static void main(String[] args) { 32 Righthand righthand = new Righthand(); 33 Lefthand lefthand = new Lefthand(); 34 Thread left = new Thread(lefthand); 35 Thread right = new Thread(righthand); 36 left.start(); 37 right.start(); 38 } 39 }*/ 40 public class TheadTest { 41 static Thread left; 42 static Thread right; 43 44 public static void main(String[] args) { 45 Lefthand rleft = new Lefthand(); 46 Runnable rright=new Righthand(); 47 left = new Thread(rleft); 48 right = new Thread(rright); 49 left.start(); 50 right.start(); 51 } 52 }
测试程序2:
l 在Elipse环境下调试教材625页程序14-1、14-2 、14-3,结合程序运行结果理解程序;
l 在Elipse环境下调试教材631页程序14-4,结合程序运行结果理解程序;
l 对比两个程序,理解线程的概念和用途;
l 掌握线程创建的两种技术。
package bounceThread; import java.awt.geom.*; /** A ball that moves and bounces off the edges of a rectangle * @version 1.33 2007-05-17 * @author Cay Horstmann */ public class Ball { private static final int XSIZE = 15; private static final int YSIZE = 15; private double x = 0; private double y = 0; private double dx = 1; private double dy = 1; /** Moves the ball to the next position, reversing direction if it hits one of the edges */ //判断球的边界所处状态的四个条件 public void move(Rectangle2D bounds) { x += dx; y += dy; if (x < bounds.getMinX()) { x = bounds.getMinX(); dx = -dx; } if (x + XSIZE >= bounds.getMaxX()) { x = bounds.getMaxX() - XSIZE; dx = -dx; } if (y < bounds.getMinY()) { y = bounds.getMinY(); dy = -dy; } if (y + YSIZE >= bounds.getMaxY()) { y = bounds.getMaxY() - YSIZE; dy = -dy; } } /** Gets the shape of the ball at its current position. */ public Ellipse2D getShape() { return new Ellipse2D.Double(x, y, XSIZE, YSIZE); } }
package bounceThread; import java.awt.*; import java.util.*; import javax.swing.*; /** * The component that draws the balls. * @version 1.34 2012-01-26 * @author Cay Horstmann */ public class BallComponent extends JComponent { private static final int DEFAULT_WIDTH = 450; private static final int DEFAULT_HEIGHT = 350; private java.util.List<Ball> balls = new ArrayList<>(); /** * Add a ball to the panel. * @param b the ball to add */ public void add(Ball b) { balls.add(b); } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; for (Ball b : balls) { g2.fill(b.getShape()); } } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } }
package bounce; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Shows an animated bouncing ball. * @version 1.34 2015-06-21 * @author Cay Horstmann */ public class Bounce { public static void main(String[] args) { EventQueue.invokeLater(() -> { JFrame frame = new BounceFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } } /** * The frame with ball component and buttons. */ class BounceFrame extends JFrame { private BallComponent comp; public static final int STEPS = 1000; public static final int DELAY = 3; /** * Constructs the frame with the component for showing the bouncing ball and * Start and Close buttons */ public BounceFrame() { setTitle("Bounce"); comp = new BallComponent(); add(comp, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "Start", event -> addBall()); addButton(buttonPanel, "Close", event -> System.exit(0)); add(buttonPanel, BorderLayout.SOUTH);//将buttonPanel组件整体放在南端 pack(); } /** * Adds a button to a container. * @param c the container * @param title the button title * @param listener the action listener for the button */ public void addButton(Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } /** * Adds a bouncing ball to the panel and makes it bounce 1,000 times. */ public void addBall() { try { Ball ball = new Ball(); comp.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(comp.getBounds());//调用move方法 comp.paint(comp.getGraphics()); Thread.sleep(DELAY);//调用线程的sleep方法 } } catch (InterruptedException e) { } } }
14-4的程序
package bounceThread; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Shows animated bouncing balls. * @version 1.34 2015-06-21 * @author Cay Horstmann */ public class BounceThread { public static void main(String[] args) { EventQueue.invokeLater(() -> { JFrame frame = new BounceFrame(); frame.setTitle("BounceThread"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } } /** * The frame with panel and buttons. */ class BounceFrame extends JFrame { private BallComponent comp; public static final int STEPS = 1000; public static final int DELAY = 5; /** * Constructs the frame with the component for showing the bouncing ball and * Start and Close buttons */ public BounceFrame() { comp = new BallComponent(); add(comp, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "Start", event -> addBall()); addButton(buttonPanel, "Close", event -> System.exit(0)); add(buttonPanel, BorderLayout.SOUTH); pack(); } /** * Adds a button to a container. * @param c the container * @param title the button title * @param listener the action listener for the button */ public void addButton(Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } /** * Adds a bouncing ball to the canvas and starts a thread to make it bounce */ public void addBall() { Ball ball = new Ball(); comp.add(ball); //引用实现了Runnable的方法 Runnable r = () -> { try { for (int i = 1; i <= STEPS; i++) { ball.move(comp.getBounds()); comp.repaint(); Thread.sleep(DELAY); } } catch (InterruptedException e) { } }; Thread t = new Thread(r);//用Runnable创建一个Thread对象 t.start();//启动线程 } }
测试程序3:分析以下程序运行结果并理解程序。
1 class Race extends Thread { 2 public static void main(String args[]) { 3 Race[] runner = new Race[4]; 4 for (int i = 0; i < 4; i++) 5 runner[i] = new Race(); 6 for (int i = 0; i < 4; i++) 7 runner[i].start(); 8 runner[1].setPriority(MIN_PRIORITY); 9 runner[3].setPriority(MAX_PRIORITY); 10 } 11 12 public void run() { 13 for (int i = 0; i < 1000000; i++);//用来延时,相当于Sleep,但不会释放CPU 14 System.out.println(getName() + "线程的优先级是" + getPriority() + "已计算完毕!"); 15 } 16 }
测试程序4:
l 教材642页程序模拟一个有若干账户的银行,随机地生成在这些账户之间转移钱款的交易。每一个账户有一个线程。在每一笔交易中,会从线程所服务的账户中随机转移一定数目的钱款到另一个随机账户。
l 在Elipse环境下调试教材642页程序14-5、14-6,结合程序运行结果理解程序;
1 package synch; 2 3 import java.util.*; 4 import java.util.concurrent.locks.*; 5 6 /** 7 * A bank with a number of bank accounts that uses locks for serializing access. 8 * @version 1.30 2004-08-01 9 * @author Cay Horstmann 10 */ 11 public class Bank 12 { 13 private final double[] accounts; 14 private Lock bankLock; 15 private Condition sufficientFunds; 16 17 /** 18 * Constructs the bank. 19 * @param n the number of accounts 20 * @param initialBalance the initial balance for each account 21 */ 22 public Bank(int n, double initialBalance) 23 { 24 accounts = new double[n]; 25 Arrays.fill(accounts, initialBalance);//将指定的 double 值分配给指定 double 型数组的每个元素 26 bankLock = new ReentrantLock(); 27 sufficientFunds = bankLock.newCondition();//返回绑定到此 Lock 实例的新 Condition 实例 28 } 29 30 /** 31 * Transfers money from one account to another. 32 * @param from the account to transfer from 33 * @param to the account to transfer to 34 * @param amount the amount to transfer 35 */ 36 public void transfer(int from, int to, double amount) throws InterruptedException 37 { 38 bankLock.lock();//获取锁 39 try 40 { 41 while (accounts[from] < amount) 42 sufficientFunds.await();//造成当前线程在接到信号或被中断之前一直处于等待状态 43 System.out.print(Thread.currentThread()); 44 accounts[from] -= amount; 45 System.out.printf(" %10.2f from %d to %d", amount, from, to); 46 accounts[to] += amount; 47 System.out.printf(" Total Balance: %10.2f%n", getTotalBalance()); 48 sufficientFunds.signalAll();//唤醒所有等待线程 49 } 50 finally 51 { 52 bankLock.unlock();//释放锁 53 } 54 } 55 56 /** 57 * Gets the sum of all account balances. 58 * @return the total balance 59 */ 60 public double getTotalBalance() 61 { 62 bankLock.lock(); 63 try 64 { 65 double sum = 0; 66 67 for (double a : accounts) 68 sum += a; 69 70 return sum; 71 } 72 finally 73 { 74 bankLock.unlock(); 75 } 76 } 77 78 /** 79 * Gets the number of accounts in the bank. 80 * @return the number of accounts 81 */ 82 public int size() 83 { 84 return accounts.length; 85 } 86 }
1 package synch; 2 3 /** 4 * This program shows how multiple threads can safely access a data structure. 5 * @version 1.31 2015-06-21 6 * @author Cay Horstmann 7 */ 8 public class SynchBankTest 9 { 10 public static final int NACCOUNTS = 100; 11 public static final double INITIAL_BALANCE = 1000; 12 public static final double MAX_AMOUNT = 1000; 13 public static final int DELAY = 10; 14 15 public static void main(String[] args) 16 { 17 Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE); 18 for (int i = 0; i < NACCOUNTS; i++) 19 { 20 int fromAccount = i; 21 Runnable r = () -> {//用Lambda表达式简化代码 22 try 23 { 24 while (true) 25 { 26 int toAccount = (int) (bank.size() * Math.random()); 27 double amount = MAX_AMOUNT * Math.random(); 28 bank.transfer(fromAccount, toAccount, amount); 29 Thread.sleep((int) (DELAY * Math.random())); 30 } 31 } 32 catch (InterruptedException e) 33 { 34 } 35 }; 36 Thread t = new Thread(r); 37 t.start(); 38 } 39 } 40 }
综合编程练习
编程练习1
1.设计一个用户信息采集程序,要求如下:
(1) 用户信息输入界面如下图所示:
(2) 用户点击提交按钮时,用户输入信息显示控制台界面;
(3) 用户点击重置按钮后,清空用户已输入信息;
(4) 点击窗口关闭,程序退出。
1 package 第十六周; 2 3 import java.awt.EventQueue; 4 5 import javax.swing.JFrame; 6 7 public class Mian { 8 public static void main(String[] args) { 9 EventQueue.invokeLater(() -> { 10 DemoJFrame page = new DemoJFrame(); 11 }); 12 } 13 }
1 package 第十六周; 2 import java.awt.Dimension; 3 import java.awt.Toolkit; 4 import java.awt.Window; 5 6 public class WinCenter { 7 public static void center(Window win){ 8 Toolkit tkit = Toolkit.getDefaultToolkit();//获取默认工具包 9 Dimension sSize = tkit.getScreenSize();//获取屏幕的大小 10 Dimension wSize = win.getSize(); 11 if(wSize.height > sSize.height){ 12 wSize.height = sSize.height; 13 } 14 if(wSize.width > sSize.width){ 15 wSize.width = sSize.width; 16 } 17 win.setLocation((sSize.width - wSize.width)/ 2, (sSize.height - wSize.height)/ 2);//将组件移到新的位置 18 } 19 }
1 package 第十六周; 2 import java.awt.Color; 3 import java.awt.Dimension; 4 import java.awt.FlowLayout; 5 import java.awt.GridLayout; 6 import java.awt.LayoutManager; 7 import java.awt.Panel; 8 import java.awt.event.ActionEvent; 9 import java.awt.event.ActionListener; 10 import java.io.BufferedReader; 11 import java.io.File; 12 import java.io.FileInputStream; 13 import java.io.IOException; 14 import java.io.InputStreamReader; 15 import java.util.ArrayList; 16 import java.util.Timer; 17 import java.util.TimerTask; 18 19 import javax.swing.BorderFactory; 20 import javax.swing.ButtonGroup; 21 import javax.swing.ButtonModel; 22 import javax.swing.JButton; 23 import javax.swing.JCheckBox; 24 import javax.swing.JComboBox; 25 import javax.swing.JFrame; 26 import javax.swing.JLabel; 27 import javax.swing.JPanel; 28 import javax.swing.JRadioButton; 29 import javax.swing.JTextField; 30 31 public class DemoJFrame extends JFrame { 32 private JPanel jPanel1; 33 private JPanel jPanel2; 34 private JPanel jPanel3; 35 private JPanel jPanel4; 36 private JTextField fieldname; 37 private JComboBox comboBox; 38 private JTextField fieldadress; 39 private ButtonGroup bg; 40 private JRadioButton nan; 41 private JRadioButton nv; 42 private JCheckBox sing; 43 private JCheckBox dance; 44 private JCheckBox draw; 45 46 public DemoJFrame() { 47 // 设置窗口大小 48 this.setSize(800, 400); 49 // 设置可见性 50 this.setVisible(true); 51 // 设置标题 52 this.setTitle("Student Detail"); 53 // 设置关闭操作 54 this.setDefaultCloseOperation(EXIT_ON_CLOSE); 55 // 设置窗口居中 56 WinCenter.center(this); 57 // 创建四个面板对象 58 jPanel1 = new JPanel(); 59 setJPanel1(jPanel1); 60 jPanel2 = new JPanel(); 61 setJPanel2(jPanel2); 62 jPanel3 = new JPanel(); 63 setJPanel3(jPanel3); 64 jPanel4 = new JPanel(); 65 setJPanel4(jPanel4); 66 // 设置容器为流式布局 67 FlowLayout flowLayout = new FlowLayout(); 68 this.setLayout(flowLayout); 69 // 将四个面板添加到容器中 70 this.add(jPanel1); 71 this.add(jPanel2); 72 this.add(jPanel3); 73 this.add(jPanel4); 74 75 } 76 77 /* 78 * 设置面一 79 */ 80 private void setJPanel1(JPanel jPanel) { 81 jPanel.setPreferredSize(new Dimension(700, 45));//设置此组件的首选大小 82 // 给面板的布局设置为网格布局 一行4列 83 jPanel.setLayout(new GridLayout(1, 4)); 84 JLabel name = new JLabel("Name:"); 85 name.setSize(100, 50); 86 fieldname = new JTextField(""); 87 fieldname.setSize(80, 20); 88 JLabel study = new JLabel("Qualification:"); 89 comboBox = new JComboBox(); 90 comboBox.addItem("Graduate"); 91 comboBox.addItem("senior"); 92 comboBox.addItem("Undergraduate"); 93 jPanel.add(name); 94 jPanel.add(fieldname); 95 jPanel.add(study); 96 jPanel.add(comboBox); 97 98 } 99 100 /* 101 * 设置面板二 102 */ 103 private void setJPanel2(JPanel jPanel) { 104 jPanel.setPreferredSize(new Dimension(700, 50)); 105 // 给面板的布局设置为网格布局 一行4列 106 jPanel.setLayout(new GridLayout(1, 4)); 107 JLabel name = new JLabel("Address:"); 108 fieldadress = new JTextField(); 109 fieldadress.setPreferredSize(new Dimension(150, 50)); 110 JLabel study = new JLabel("Hobby:"); 111 JPanel selectBox = new JPanel(); 112 selectBox.setBorder(BorderFactory.createTitledBorder("")); 113 selectBox.setLayout(new GridLayout(3, 1)); 114 sing = new JCheckBox("Singing"); 115 dance = new JCheckBox("Dancing"); 116 draw = new JCheckBox("Reading"); 117 selectBox.add(sing); 118 selectBox.add(dance); 119 selectBox.add(draw); 120 jPanel.add(name); 121 jPanel.add(fieldadress); 122 jPanel.add(study); 123 jPanel.add(selectBox); 124 } 125 126 /* 127 * 设置面板三 128 */ 129 private void setJPanel3(JPanel jPanel) { 130 jPanel.setPreferredSize(new Dimension(700, 150)); 131 FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT); 132 jPanel.setLayout(flowLayout); 133 JLabel sex = new JLabel("Sex:"); 134 JPanel selectBox = new JPanel(); 135 selectBox.setBorder(BorderFactory.createTitledBorder("")); 136 selectBox.setLayout(new GridLayout(2, 1)); 137 bg = new ButtonGroup(); 138 nan = new JRadioButton("Male"); 139 nv = new JRadioButton("Female"); 140 bg.add(nan); 141 bg.add(nv); 142 selectBox.add(nan); 143 selectBox.add(nv); 144 jPanel.add(sex); 145 jPanel.add(selectBox); 146 147 } 148 149 /* 150 * 设置面板四 151 */ 152 private void setJPanel4(JPanel jPanel) { 153 // TODO 自动生成的方法存根 154 jPanel.setPreferredSize(new Dimension(700, 150)); 155 FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER, 50, 10); 156 jPanel.setLayout(flowLayout); 157 jPanel.setLayout(flowLayout); 158 JButton sublite = new JButton("Validate"); 159 JButton reset = new JButton("Reset"); 160 sublite.addActionListener((e) -> valiData()); 161 reset.addActionListener((e) -> Reset()); 162 jPanel.add(sublite); 163 jPanel.add(reset); 164 } 165 166 /* 167 * 提交数据 168 */ 169 private void valiData() { 170 // 拿到数据 171 String name = fieldname.getText().toString().trim(); 172 String xueli = comboBox.getSelectedItem().toString().trim(); 173 String address = fieldadress.getText().toString().trim(); 174 System.out.println(name); 175 System.out.println(xueli); 176 String hobbystring=""; 177 if (sing.isSelected()) { 178 hobbystring+="Singing "; 179 } 180 if (dance.isSelected()) { 181 hobbystring+="Dancing "; 182 } 183 if (draw.isSelected()) { 184 hobbystring+="Reading "; 185 } 186 System.out.println(address); 187 if (nan.isSelected()) { 188 System.out.println("Male"); 189 } 190 if (nv.isSelected()) { 191 System.out.println("Female"); 192 } 193 System.out.println(hobbystring); 194 } 195 196 /* 197 * 重置 198 */ 199 private void Reset() { 200 fieldadress.setText(null); 201 fieldname.setText(null); 202 comboBox.setSelectedIndex(0); 203 sing.setSelected(false); 204 dance.setSelected(false); 205 draw.setSelected(false); 206 bg.clearSelection(); 207 } 208 }
输入信息并提交:
点击重置:
2.创建两个线程,每个线程按顺序输出5次“你好”,每个“你好”要标明来自哪个线程及其顺序号。
1 class Lefthand extends Thread { 2 3 public void run() 4 5 { 6 7 for(int i=0;i<=4;i++) 8 9 { System.out.println("1.你好"); 10 11 try{ sleep(500); } 12 13 catch(InterruptedException e) 14 15 { System.out.println("Lefthand error.");} 16 17 } 18 19 } 20 21 } 22 23 class Righthand extends Thread { 24 25 public void run() 26 27 { 28 29 for(int i=0;i<=4;i++) 30 31 { System.out.println("2.你好"); 32 33 try{ sleep(300); } 34 35 catch(InterruptedException e) 36 37 { System.out.println("Righthand error.");} 38 39 } 40 41 } 42 43 } 44 45 public class ThreadTest 46 47 { 48 49 static Lefthand left; 50 51 static Righthand right; 52 53 public static void main(String[] args) 54 55 { left=new Lefthand(); 56 57 right=new Righthand(); 58 59 left.start(); 60 61 right.start(); 62 63 } 64 65 }
3.实验总结:
本周主要学习了与线程有关的知识,我学会了线程的创建方法,但在实际操作中任然有一定的难度,在老师和助教学长的帮助下完成了用Runnale方法创建线程的任务,理解了线程的优先级属性及调度方法,学到了终止线程的方法,总的来说,本周的学习还算顺利。