项目 |
内容 |
这个作业属于哪个课程 |
https://www.cnblogs.com/nwnu-daizh/ |
这个作业的要求在哪里 |
https://www.cnblogs.com/nwnu-daizh/p/12031970.html |
作业学习目标 |
(1) 掌握Java应用程序的打包操作; (2) 掌握线程概念; (3) 掌握线程创建的两种技术。 |
第一部分:总结教材14.1-14.3知识内容
14.1什么是线程
1.进程--概念
要解释线程,就必须明白什么是进程。
什么是进程呢?
进程是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间),比如用户点击桌面的IE浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间。当用户再次点击左面的IE浏览器,又启动了一个进程,操作系统将为新的进程分配新的独立的地址空间。目前操作系统都支持多进程。
要点:用户每启动一个进程,操作系统就会为该进程分配一个独立的内存空间。
2.线程--概念
在明白进程后,就比较容易理解线程的概念。
什么是线程呢?
是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。线程有就绪、阻塞和运行三种基本状态。
3.线程
1、线程是轻量级的进程
2、线程没有独立的地址空间(内存空间)
3、线程是由进程创建的(寄生在进程)
4、一个进程可以拥有多个线程-->这就是我们常说的多线程编程
5、线程有几种状态:
a、新建状态(new)
b、就绪状态(Runnable)
c、运行状态(Running)
d、阻塞状态(Blocked)
e、死亡状态(Dead)
4.线程有什么用处
java程序中流传一句话,不会使用线程就别跟别人说自己学过java。目前绝大部分应用程序都会涉及到多并发的问题。只要应用程序涉及到并发,就离不开多线程编程。
5.线程--如何使用
在java中一个类要当作线程来使用有两种方法。
1、继承Thread类,并重写run函数
2、实现Runnable接口,并重写run函数
因为java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能java设计者们提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程。
14.2中断线程
Terminated (被终止) 线程被终止的原因有二:
(1)一是run()方法中最后一个语句执行完毕而自 然死亡。
(2)二是因为一个没有捕获的异常终止了run方法 而意外死亡。
可以调用线程的stop 方 法 杀 死 一 个 线 程 (thread.stop();),但是,stop方法已过时, 不要在自己的代码中调用它。
其他判断和影响线程状态的方法:
(1)join():等待指定线程的终止。
(2)join(long millis):经过指定时间等待终止指定 的线程。
(3)isAlive():测试当前线程是否在活动。
(4)yield():让当前线程由“运行状态”进入到“就 绪状态”,从而让其它具有相同优先级的等待线程 获取执行权。
14.3线程状态
Java中线程的状态分为6种。
1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
3. 阻塞(BLOCKED):表示线程阻塞于锁。
4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
6. 终止(TERMINATED):表示该线程已经执行完毕。
这6种状态定义在Thread类的State枚举中,可查看源码进行一一对应。
线程的状态图
第二部分:实验部分
1、实验目的与要求
(1) 掌握Java应用程序的打包操作;
(2) 掌握线程概念;
(3) 掌握线程创建的两种技术。
2、实验内容和步骤
实验1: 导入第13章示例程序,测试程序并进行代码注释。
测试程序1
l 在elipse IDE中调试运行教材585页程序13-1,结合程序运行结果理解程序;
l 将所生成的JAR文件移到另外一个不同的目录中,再运行该归档文件,以便确认程序是从JAR文件中,而不是从当前目录中读取的资源。
l 掌握创建JAR文件的方法;
程序代码如下:
1 package resource; 2 3 import java.awt.*; 4 import java.io.*; 5 import java.net.*; 6 import java.util.*; 7 import javax.swing.*; 8 9 /** 10 * @version 1.41 2015-06-12 11 * @author Cay Horstmann 12 */ 13 public class ResourceTest 14 { 15 public static void main(String[] args) 16 { 17 EventQueue.invokeLater(() -> { 18 JFrame frame = new ResourceTestFrame(); 19 frame.setTitle("ResourceTest"); 20 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 21 frame.setVisible(true); 22 }); 23 } 24 } 25 26 /** 27 * 一个加载图像和文本资源的框架。 28 */ 29 class ResourceTestFrame extends JFrame 30 { 31 private static final int DEFAULT_WIDTH = 300; 32 private static final int DEFAULT_HEIGHT = 300; 33 34 public ResourceTestFrame() 35 { 36 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 37 38 //在找到ResourceTest类的地方查找about.gif文件 39 URL aboutURL = getClass().getResource("about.gif"); 40 41 //将此图像设置为框架的图标 42 Image img = new ImageIcon(aboutURL).getImage(); 43 setIconImage(img); 44 45 JTextArea textArea = new JTextArea(); 46 47 //getResourceAsStream方法的作用是找到与类位于同一位置的资源,返回一个可以加载资源的URL或者输入流 48 InputStream stream = getClass().getResourceAsStream("about.txt"); 49 50 //在读取文本时使用同一编码UTF-8 51 try (Scanner in = new Scanner(stream, "UTF-8")) 52 { 53 while (in.hasNext()) 54 textArea.append(in.nextLine() + " "); 55 } 56 add(textArea); 57 } 58 }
运行截图如下:
归档截图如下:
打开后:
测试程序2:
l 在elipse IDE中调试运行ThreadTest,结合程序运行结果理解程序;
l 掌握线程概念;
l 掌握用Thread的扩展类实现线程的方法;
l 利用Runnable接口改造程序,掌握用Runnable接口创建线程的方法。
程序代码如下:1 package ThreadTest; 2 3 class Lefthand extends Thread { 4 public void run() 5 { 6 for(int i=0;i<=5;i++) 7 { System.out.println("You are Students!"); 8 //调用Thread的sleep方法不会创建一个新线程, 9 //sleep是Thread的静态方法,用于暂停当前线程的活动 10 try{ 11 sleep(500); 12 } 13 catch(InterruptedException e) 14 { 15 System.out.println("Lefthand error."); 16 } 17 } 18 } 19 } 20 class Righthand extends Thread { 21 public void run() 22 { 23 for(int i=0;i<=5;i++) 24 { System.out.println("I am a Teacher!"); 25 try{ 26 sleep(300); 27 } 28 catch(InterruptedException e) 29 { 30 System.out.println("Righthand error."); 31 } 32 } 33 } 34 } 35 public class ThreadTest 36 { 37 static Lefthand left; 38 static Righthand right; 39 public static void main(String[] args) 40 { left=new Lefthand(); 41 right=new Righthand(); 42 //同时启动两个线程 43 left.start(); 44 right.start(); 45 } 46 }
Runnable接口改造的程序如下:
1 package Thread 2 //实现Runnable接口的类实现多线程 3 class Lefthand implements Runnable{ 4 public void run() 5 { 6 7 for(int i=0;i<=5;i++) 8 { System.out.println("You are Students!"); 9 try{ Thread.sleep(500); }//500毫秒打印一次 10 catch(InterruptedException e)//中断异常 11 { System.out.println("Lefthand error.");} 12 } 13 } 14 } 15 class Righthand implements Runnable { 16 public void run() 17 { 18 for(int i=0;i<=5;i++) 19 { System.out.println("I am a Teacher!"); 20 try{ Thread.sleep(300); }//300毫秒打印一次 21 catch(InterruptedException e) 22 { System.out.println("Righthand error.");} 23 } 24 } 25 } 26 public class ThreadTest 27 { 28 static Thread left; 29 static Thread right; 30 public static void main(String[] args) 31 { 32 Runnable lefthand = new Lefthand(); 33 left=new Thread(lefthand); 34 left.start(); 35 Runnable righthand = new Righthand(); 36 right=new Thread(righthand); 37 right.start(); 38 39 } 40 }
运行截图如下:
测试程序3:
l 在Elipse环境下调试教材625页程序14-1、14-2 、14-3,结合程序运行结果理解程序;
l 在Elipse环境下调试教材631页程序14-4,结合程序运行结果理解程序;
l 对比两个程序,理解线程的概念和用途;
l 掌握线程创建的两种技术。
程序代码如下:
1 package bounce; 2 3 import java.awt.geom.*; 4 5 /** 6 * 在长方形边缘上移动和反弹的球 7 * @version 1.33 2007-05-17 8 * @author Cay Horstmann 9 */ 10 public class Ball 11 { 12 private static final int XSIZE = 15; 13 private static final int YSIZE = 15; 14 private double x = 0; 15 private double y = 0; 16 private double dx = 1; 17 private double dy = 1; 18 19 /** 20 * 将球移动到下一个位置,如果碰到其中一个边,则反转方向 21 */ 22 public void move(Rectangle2D bounds) 23 { 24 x += dx; 25 y += dy; 26 //宽度上的最小位置 27 if (x < bounds.getMinX()) 28 { 29 x = bounds.getMinX(); 30 dx = -dx; 31 } 32 //宽度上的最大位置 33 if (x + XSIZE >= bounds.getMaxX()) 34 { 35 x = bounds.getMaxX() - XSIZE; 36 dx = -dx; 37 } 38 //高度上的最小位置 39 if (y < bounds.getMinY()) 40 { 41 y = bounds.getMinY(); 42 dy = -dy; 43 } 44 //宽度上的最大位置 45 if (y + YSIZE >= bounds.getMaxY()) 46 { 47 y = bounds.getMaxY() - YSIZE; 48 dy = -dy; 49 } 50 } 51 52 /** 53 * 获取球在其当前位置的形状 54 */ 55 public Ellipse2D getShape() 56 { 57 return new Ellipse2D.Double(x, y, XSIZE, YSIZE); 58 } 59 }
1 package bounce; 2 3 import java.awt.*; 4 import java.util.*; 5 import javax.swing.*; 6 7 /** 8 * 画弹力球的部件. 9 * @version 1.34 2012-01-26 10 * @author Cay Horstmann 11 */ 12 public class BallComponent extends JPanel 13 { 14 private static final int DEFAULT_WIDTH = 450; 15 private static final int DEFAULT_HEIGHT = 350; 16 17 private java.util.List<Ball> balls = new ArrayList<>(); 18 19 /** 20 * 增加一个球到组件上。 21 * @param b the ball to add 22 */ 23 24 //创建add方法,在add方法中使用球类型集合的add方法向集合中添加球 25 public void add(Ball b) 26 { 27 balls.add(b); 28 } 29 30 //paintComponent方法中有一个Graphics类型的参数,这个参数保留着用于绘制图像和文本的设置。 31 //在Java中,所有的绘制都必须使用Graphics对象,其中包含了绘制图案,图像和文本的方法。 32 public void paintComponent(Graphics g) 33 { 34 super.paintComponent(g); // 使用背景色绘制面板 35 Graphics2D g2 = (Graphics2D) g; 36 37 //获取每一个球的位置和形状并使用默认颜色进行填充 38 for (Ball b : balls) 39 { 40 g2.fill(b.getShape()); 41 } 42 } 43 44 public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } 45 }
1 package bounce; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 /** 8 * 显示动画弹跳球。 9 * @version 1.34 2015-06-21 10 * @author Cay Horstmann 11 */ 12 public class Bounce 13 { 14 public static void main(String[] args) 15 { 16 EventQueue.invokeLater(() -> { 17 JFrame frame = new BounceFrame(); 18 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 19 frame.setVisible(true); 20 }); 21 } 22 } 23 24 /** 25 * 有球部件和按钮的框架。 26 */ 27 class BounceFrame extends JFrame 28 { 29 private BallComponent comp; 30 public static final int STEPS = 1000; 31 public static final int DELAY = 3; 32 33 /** 34 * 构造包含用于显示弹跳球和启动和关闭按钮的框架 35 */ 36 public BounceFrame() 37 { 38 setTitle("Bounce"); 39 comp = new BallComponent(); 40 add(comp, BorderLayout.CENTER); 41 JPanel buttonPanel = new JPanel(); 42 43 //使用addBuuton方法为按钮添加标题,监听器,并且将按钮添加至面板中 44 addButton(buttonPanel, "Start", event -> addBall()); 45 addButton(buttonPanel, "Close", event -> System.exit(0)); 46 47 //将按钮面板添加至框架的南部 48 add(buttonPanel, BorderLayout.SOUTH); 49 pack(); 50 } 51 52 /** 53 *向容器添加按钮 54 * @param c the container 55 * @param 为按钮设置标题 56 * @param 为按钮设置监听器 57 */ 58 public void addButton(Container c, String title, ActionListener listener) 59 { 60 JButton button = new JButton(title); 61 c.add(button); 62 button.addActionListener(listener); 63 } 64 65 /** 66 * 在面板中添加一个弹跳球,使其弹跳1000次。 67 */ 68 public void addBall() 69 { 70 try 71 { 72 Ball ball = new Ball(); 73 comp.add(ball); 74 75 for (int i = 1; i <= STEPS; i++) 76 { 77 //这样设置的话所有球的移动都处于一个线程当中 78 ball.move(comp.getBounds()); 79 comp.paint(comp.getGraphics()); 80 Thread.sleep(DELAY); 81 } 82 } 83 //中断异常 84 catch (InterruptedException e) 85 { 86 } 87 } 88 }
运行结果如下:
Ball类程序代码如下:
1 package bounce; 2 3 import java.awt.geom.*; 4 5 /** 6 * 在长方形边缘上移动和反弹的球 7 * @version 1.33 2007-05-17 8 * @author Cay Horstmann 9 */ 10 public class Ball 11 { 12 private static final int XSIZE = 15; 13 private static final int YSIZE = 15; 14 private double x = 0; 15 private double y = 0; 16 private double dx = 1; 17 private double dy = 1; 18 19 /** 20 * 将球移动到下一个位置,如果碰到其中一个边,则反转方向 21 */ 22 public void move(Rectangle2D bounds) 23 { 24 x += dx; 25 y += dy; 26 //宽度上的最小位置 27 if (x < bounds.getMinX()) 28 { 29 x = bounds.getMinX(); 30 dx = -dx; 31 } 32 //宽度上的最大位置 33 if (x + XSIZE >= bounds.getMaxX()) 34 { 35 x = bounds.getMaxX() - XSIZE; 36 dx = -dx; 37 } 38 //高度上的最小位置 39 if (y < bounds.getMinY()) 40 { 41 y = bounds.getMinY(); 42 dy = -dy; 43 } 44 //宽度上的最大位置 45 if (y + YSIZE >= bounds.getMaxY()) 46 { 47 y = bounds.getMaxY() - YSIZE; 48 dy = -dy; 49 } 50 } 51 52 /** 53 * 获取球在其当前位置的形状 54 */ 55 public Ellipse2D getShape() 56 { 57 return new Ellipse2D.Double(x, y, XSIZE, YSIZE); 58 } 59 }
BallComponent类代码如下:
1 package bounce; 2 3 import java.awt.*; 4 import java.util.*; 5 import javax.swing.*; 6 7 /** 8 * 画弹力球的部件. 9 * @version 1.34 2012-01-26 10 * @author Cay Horstmann 11 */ 12 public class BallComponent extends JPanel 13 { 14 private static final int DEFAULT_WIDTH = 450; 15 private static final int DEFAULT_HEIGHT = 350; 16 17 private java.util.List<Ball> balls = new ArrayList<>(); 18 19 /** 20 * 增加一个球到组件上。 21 * @param b the ball to add 22 */ 23 24 //创建add方法,在add方法中使用球类型集合的add方法向集合中添加球 25 public void add(Ball b) 26 { 27 balls.add(b); 28 } 29 30 //paintComponent方法中有一个Graphics类型的参数,这个参数保留着用于绘制图像和文本的设置。 31 //在Java中,所有的绘制都必须使用Graphics对象,其中包含了绘制图案,图像和文本的方法。 32 public void paintComponent(Graphics g) 33 { 34 super.paintComponent(g); // 使用背景色绘制面板 35 Graphics2D g2 = (Graphics2D) g; 36 37 //获取每一个球的位置和形状并使用默认颜色进行填充 38 for (Ball b : balls) 39 { 40 g2.fill(b.getShape()); 41 } 42 } 43 44 public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } 45 }
BounceThread类代码如下:
1 package bounceThread; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 6 import javax.swing.*; 7 8 /** 9 * 显示动画弹跳球。 10 * @version 1.34 2015-06-21 11 * @author Cay Horstmann 12 */ 13 public class BounceThread 14 { 15 public static void main(String[] args) 16 { 17 EventQueue.invokeLater(() -> { 18 JFrame frame = new BounceFrame(); 19 frame.setTitle("BounceThread"); 20 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 21 frame.setVisible(true); 22 }); 23 } 24 } 25 26 /** 27 * 有面板和按钮的框架。 28 */ 29 class BounceFrame extends JFrame 30 { 31 private BallComponent comp; 32 public static final int STEPS = 1000; 33 public static final int DELAY = 5; 34 35 36 /** 37 * 构造包含用于显示弹跳球和开始和关闭按钮的组件的框架 38 */ 39 public BounceFrame() 40 { 41 comp = new BallComponent(); 42 add(comp, BorderLayout.CENTER); 43 JPanel buttonPanel = new JPanel(); 44 addButton(buttonPanel, "Start", event -> addBall()); 45 addButton(buttonPanel, "Close", event -> System.exit(0)); 46 add(buttonPanel, BorderLayout.SOUTH); 47 pack(); 48 } 49 50 /** 51 * 添加一个按钮到框架中. 52 * @param c the container 53 * @param 为按钮设置标题 54 * @param 为按钮设置监听器 55 */ 56 public void addButton(Container c, String title, ActionListener listener) 57 { 58 JButton button = new JButton(title); 59 c.add(button); 60 button.addActionListener(listener); 61 } 62 63 /** 64 * 在画布上添加一个弹跳球并开始一条线使其弹跳 65 */ 66 public void addBall() 67 { 68 Ball ball = new Ball(); 69 comp.add(ball); 70 71 //将移动球的代码放置在一个独立的线程中,运行这段代码可以提高弹跳球的相应性能 72 //实现一个BallRunnable类,然后,将动画代码放在run方法中,这样就即将动画代码放在了一个单独的线程中 73 Runnable r = () -> { 74 try 75 { 76 for (int i = 1; i <= STEPS; i++) 77 { 78 ball.move(comp.getBounds()); 79 //调用组件的repaint方法,重新绘制组件 80 comp.repaint(); 81 Thread.sleep(DELAY); 82 } 83 } 84 catch (InterruptedException e) 85 { 86 } 87 }; 88 89 //将Runnable对象作为入口参数传入Thread的构造函数,再调用start方法就可以启动线程 90 Thread t = new Thread(r); 91 t.start(); 92 } 93 }
运行结果如下:
第三部分:实验总结
通过这次实验,我主要掌握了多线程在程序中的的实现。通过测试程序三的运行结果很直观的让我线程有了一定的认识。对本周实验由于都是测试性程序并且作业量也比较少,感觉还是比较容易完成。前几次做实验的过程中又遇到导入的程序没有错误却运行不出来这种问题,这个星期在同学的帮助下都可以运行出来了。