项目

内容

这个作业属于哪个课程

https://www.cnblogs.com/nwnu-daizh/

这个作业的要求在哪里

https://www.cnblogs.com/nwnu-daizh/p/12031970.html

作业学习目标

(1) 掌握Java应用程序的打包操作;

(2) 掌握线程概念;

(3) 掌握线程创建的两种技术。

(4) 学习设计应用程序的GUI。

第一部分:总结教材14.1-14.3知识内容

14.1 什么是线程

多线程程序在较低的层次上扩展了多任务的概念:一个程序同时执行多个任务。通常,每一个任务称为一个线程( thread), 它是线程控制的简称。可以同时运行一个以上线程的程序称为多线程程序(multithreaded)。

sleep 方法可以抛出一个 IntermptedException 异常。

【API】java.Iang.Thread 1.0:

      static void sleep(long minis)

      休眠给定的毫秒数。

      参数: millis 休眠的毫秒数

14.1.1 使用线程给其他任务提供机会

下面是在一个单独的线程中执行一个任务的简单过程:
1 ) 将任务代码移到实现了 Runnable 接口的类的 run 方法中。
由于 Runnable 是一个函数式接口,可以用 lambda 表达式建立一个实例
  Runnable r = () -> { task code };
2 ) 由 Runnable 创建一个 Thread 对象
  Thread t = new Thread(r);
3 ) 启动线程
  t.start();

注释: 也可以通过构建一个 Thread 类的子类定义一个线程 。然后, 构造一个子类的对象, 并调用 start 方法。 不过, 这种方法已不再推荐。 应该将要并行运行的任务与运行机制解耦合。如果有很多任务, 要为每个任务创建一个独立的线程所付出的代价太大了。 可以使用线程池来解决这个问题。

警告: 不要调用 Thread 类或 Runnable 对象的 run 方法。 直接调用 run 方法, 只会执行同一个线程中的任务, 而不会启动新线程。 应该调用 Thread.start 方法。这个方法将创建一个执行 ran 方法的新线程

【API】java.Iang.Thread 1.0:
  ThreadCRunnable target )
    构造一个新线程, 用于调用给定目标的 run() 方法。
  void start( )
    启动这个线程, 将引发调用 run() 方法。这个方法将立即返回, 并且新线程将并发运行。
  void run( )
    调用关联 Runnable 的 run 方法。
【API】java.lang.Runnable 1.0:
  void run( )
    必须覆盖这个方法, 并在这个方法中提供所要执行的任务指令。
14.2 中断线程
在 Java 的早期版本中, 还有一个 stop方法, 其他线程可以调用它终止线程。但是, 这个方法现在已经被弃用了。
没有可以强制线程终止的方法。然而, interrupt 方法可以用来请求终止线程。
要想弄清中断状态是否被置位,首先调用静态的 Thread.currentThread 方法获得当前线程, 然后调用 islnterrupted 方法
当在一个被阻塞的线程(调用 sleep 或 wait ) 上调用 interrupt 方法时, 阻塞调用将会被Interrupted Exception 异常中断。
注释: 有两个非常类似的方法, interrupted 和 islnterrupted。Interrupted 方法是一个静态方法, 它检测当前的线程是否被中断。 而且, 调用 interrupted 方法会清除该线程的中断状态。 另一方面, islnterrupted 方法是一个实例方法, 可用来检验是否有线程被中断。调用这个方法不会改变中断状态。
【API】java.Iang.Thread 1.0:
  void interrupts()
向线程发送中断请求。线程的中断状态将被设置为 true。如果目前该线程被一个 sleep调用阻塞,那么, InterruptedException 异常被抛出。
  static boolean interrupted()
测试当前线程(即正在执行这一命令的线程)是否被中断。注意,这是一个静态方法。这一调用会产生副作用—它将当前线程的中断状态重置为 false。
  boolean islnterrupted()
测试线程是否被终止。不像静态的中断方法,这一调用不改变线程的中断状态。
  static Thread currentThread()
返回代表当前执行线程的 Thread 对象
14.3 线程状态

线程可以有如下 6 种状态:

  • New (新创建)
  • Runnable (可运行)
  • Blocked (被阻塞)
  • Waiting (等待)
  • Timed waiting (计时等待)
  • Terminated (被终止)

要确定一个线程的当前状态, 可调用 getState 方法。

14.3.1 新创建线程

当用 new 操作符创建一个新线程时, 如 newThread®, 该线程还没有开始运行。这意味着它的状态是 new。当一个线程处于新创建状态时, 程序还没有开始运行线程中的代码。在线程运行之前还有一些基础工作要做。

14.3.2 可运行线程

一旦调用 start 方法,线程处于 runnable 状态。

现在所有的桌面以及服务器操作系统都使用抢占式调度。但是,像手机这样的小型设备可能使用协作式调度。

记住,在任何给定时刻,二个可运行的线程可能正在运行也可能没有运行(这就是为什么将这个状态称为可运行而不是运行。

14.3.3 被阻塞线程和等待线程

当线程处于被阻塞或等待状态时,它暂时不活动。它不运行任何代码且消耗最少的资源。直到线程调度器重新激活它。 细节取决于它是怎样达到非活动状态的。

  当一个线程试图获取一个内部的对象锁(而不是 javiutiUoncurrent 库中的锁,) 而该锁被其他线程持有, 则该线程进人阻塞状态 。当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变成非阻塞状态
  当线程等待另一个线程通知调度器一个条件时, 它自己进入等待状态有几个方法有一个超时参数。调用它们导致线程进人计时等待(timed waiting) 状态。这一状态将一直保持到超时期满或者接收到适当的通知

14.3.4 被终止的线程

线程因如下两个原因之一而被终止:
  因为 run 方法正常退出而自然死亡。
  因为一个没有捕获的异常终止了 run 方法而意外死亡
特别是, 可以调用线程的 stop 方法杀死一个线程。 该方法抛出 ThreadDeath 错误对象 ,由此杀死线程。但是,stop 方法已过时, 不要在自己的代码中调用这个方法。
【API】java.iang.Thread 1.0:
  void join( )
等待终止指定的线程。
  void join( long millis )
等待指定的线程死亡或者经过指定的毫秒数。
  Thread.State getState () 5 . 0
得到这一线程的状态;NEW、RUNNABLE BLOCKED、 WAITING 、TIMED_WAITNG或 TERMINATED 之一。
  void stop( )
停止该线程。这一方法已过时
  void suspend()
暂停这一线程的执行。这一方法已过时。
  void resume()
恢复线程。这一方法仅仅在调用 suspend() 之后调用。这一方法已过时

第二部分:实验部分

实验1: 导入第13章示例程序,测试程序并进行代码注释。

测试程序1

l 在elipse IDE中调试运行教材585页程序13-1,结合程序运行结果理解程序;

l 将所生成的JAR文件移到另外一个不同的目录中,再运行该归档文件,以便确认程序是从JAR文件中,而不是从当前目录中读取的资源。

l 掌握创建JAR文件的方法;

package resource;

import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*; /**
* @version 1.41 2015-06-12
* @author Cay Horstmann
*/
public class ResourceTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> {
JFrame frame = new ResourceTestFrame();
frame.setTitle("ResourceTest");//设置标题
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭界面的操作
frame.setVisible(true);//设置可见性
});
}
} /**
* 一个加载图像和文本资源的框架
*/
class ResourceTestFrame extends JFrame
{
//定义像素长和宽
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 300; public ResourceTestFrame()//定义ResourceTestFrame类
{
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
//获取资源文件
URL aboutURL = getClass().getResource("about.gif");
Image img = new ImageIcon(aboutURL).getImage();
//在找到ResourceTest类的地方查找about.gif图像文件
setIconImage(img); JTextArea textArea = new JTextArea();
//读取about.txt文件
InputStream stream = getClass().getResourceAsStream("about.txt");
try (Scanner in = new Scanner(stream, "UTF-8"))
{
while (in.hasNext())
textArea.append(in.nextLine() + "\n");
}//捕获异常
add(textArea);
}
}

运行结果:

将所生成的JAR文件移到另外一个不同的目录中,再运行该归档文件:

 

  

然后我也不知道要怎么处理进行下一步了……

测试程序2:

l 在elipse IDE中调试运行ThreadTest,结合程序运行结果理解程序;

l 掌握线程概念;

l 掌握用Thread的扩展类实现线程的方法;

l 利用Runnable接口改造程序,掌握用Runnable接口创建线程的方法。

package ThreadTest;

class Lefthand extends Thread {
public void run()
{
for(int i=0;i<=5;i++)
{ System.out.println("You are Students!");
try{ sleep(500); }// 休眠时间为500毫秒
catch(InterruptedException e)// 阻塞状态
{ System.out.println("Lefthand error.");}
}
}
}
class Righthand extends Thread {
public void run()
{
for(int i=0;i<=5;i++)
{ System.out.println("I am a Teacher!");
try{ sleep(300); }// 休眠时间为300毫秒
catch(InterruptedException e)
{ System.out.println("Righthand error.");}
}
}
}
public class ThreadTest
{
static Lefthand left;
static Righthand right;
public static void main(String[] args)
{ left=new Lefthand();
right=new Righthand();
left.start();
right.start();
}
}

运行结果:

测试程序3:

l 在Elipse环境下调试教材625页程序14-1、14-2 、14-3,结合程序运行结果理解程序;

l 在Elipse环境下调试教材631页程序14-4,结合程序运行结果理解程序;

l 对比两个程序,理解线程的概念和用途;

l 掌握线程创建的两种技术。

程序14-1:

package bounce;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*; /**
* 显示一个动画弹球。
* @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);
});
}
} /**
* 框架与球组件和按钮。
*/
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();
} /**
* 将按钮添加到容器中。
* @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);
} /**
* 添加一个弹跳球到面板,使它弹跳1000次。
*/
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-2:

package bounce;

import java.awt.geom.*;

/**
*在矩形的边缘上移动和弹回的球
* @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; /**
* 将球移动到下一个位置,如果它击中其中一条边,则反向移动
*/
//判断球的边界所处状态的四个条件
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;
}
} /**
* 获取当前位置的球的形状。
*/
public Ellipse2D getShape()
{
return new Ellipse2D.Double(x, y, XSIZE, YSIZE);
}
}

程序14-3:

package bounce;

import java.awt.*;
import java.util.*;
import javax.swing.*; /**
* 绘制球的组件。
* @version 1.34 2012-01-26
* @author Cay Horstmann
*/
public class BallComponent extends JPanel
{
private static final int DEFAULT_WIDTH = 450;
private static final int DEFAULT_HEIGHT = 350; private java.util.List<Ball> balls = new ArrayList<>(); /**
* 向组件添加一个球。
* @param b the ball to add
*/
public void add(Ball b)
{
balls.add(b);
} public void paintComponent(Graphics g)
{
super.paintComponent(g); // erase background
Graphics2D g2 = (Graphics2D) g;
for (Ball b : balls)
{
g2.fill(b.getShape());
}
} public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
}

运行结果:

程序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();//启动线程
}
}
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 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);
}
}

运行结果:

两个实验对比:第一个程序非线程的,执行一次程序要等执行完才能执行下一次;第二个程序是线程的,执行第一次程序不用等执行完可以接着执行第二次操作。

实验总结:

    本周学习了Java应用程序的打包操作,有些地方还不太理解来…;我初步了解学习了关于线程的知识,并初步掌握了线程创建的两种方法。1)用Thread类的子类创建线程(2)用Runnable()接口实现线程;理解和掌握了线程的优先级属性及调度方法,学到了线程的七种状态。

201871010112-梁丽珍《面向对象程序设计(java)》第十六周学习总结的更多相关文章

  1. 201571030332 扎西平措 《面向对象程序设计Java》第八周学习总结

    <面向对象程序设计Java>第八周学习总结   项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https: ...

  2. 201771010118马昕璐《面向对象程序设计java》第八周学习总结

    第一部分:理论知识学习部分 1.接口 在Java程序设计语言中,接口不是类,而是对类的一组需求描述,由常量和一组抽象方法组成.Java为了克服单继承的缺点,Java使用了接口,一个类可以实现一个或多个 ...

  3. 201771010134杨其菊《面向对象程序设计java》第八周学习总结

    第八周学习总结 第一部分:理论知识 一.接口.lambda和内部类:  Comparator与comparable接口: 1.comparable接口的方法是compareTo,只有一个参数:comp ...

  4. 201771010134杨其菊《面向对象程序设计java》第七周学习总结

    第七周学习总结 第一部分:理论知识 1.继承是面向对象程序设计(Object Oriented Programming-OOP)中软件重用的关键技术.继承机制使用已经定义的类作为基础建立新的类定义,新 ...

  5. 201771010128 王玉兰《面象对象程序设计 (Java) 》第六周学习总结

    ---恢复内容开始--- 第一部分:基础知识总结: 1.继承 A:用已有类来构建新类的一种机制,当定义了一个新类继承一个类时,这个新类就继承了这个类的方法和域以适应新的情况: B:特点:具有层次结构. ...

  6. 201871010126 王亚涛《面向对象程序设计 JAVA》 第十三周学习总结

      内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/ ...

  7. 马凯军201771010116《面向对象程序设计Java》第八周学习总结

    一,理论知识学习部分 6.1.1 接口概念 两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构:二,一个类所具有的方法的特征集合,是一种逻辑上的抽象.前者叫做“Java接口”,后 ...

  8. 周强201771010141《面向对象程序设计Java》第八周学习总结

    一.理论知识学习部分 Java为了克服单继承的缺点,Java使用了接口,一个类可以实现一个或多个接口. 接口体中包含常量定义和方法定义,接口中只进行方法的声明,不提供方法的实现. 类似建立类的继承关系 ...

  9. 201777010217-金云馨《面向对象程序设计Java》第八周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  10. 201871010126 王亚涛 《面向对象程序设计 (Java)》第十七周学习总结

    内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/12 ...

随机推荐

  1. react中报错Failed to set an indexed property on 'CSSStyleDeclaration': Index property setter is not supported

    产生这个报错的原因是我当时将样式写到了less文件,我在div中使用的使用应该是使用className = ,而我误写了一个style = .style里面当然没有自定义的className,所以产生 ...

  2. Prometheus学习系列(七)之Prometheus PromQL说明

    前言 本文来自Prometheus官网手册1.2.3 和 Prometheus简介1.2.3 PromQL操作符 一.二元操作符 Prometheus的查询语言支持基本的逻辑运算和算术运算.对于两个瞬 ...

  3. DataGridView使用自定义控件实现简单分页功能

    本例子使用自定义控件方法实现,数据库使用的是SQL Server,实现过程如下: 1.新建一个自定义控件,命名为:PageControl. 2.PageControl代码如下: public part ...

  4. leaflet 结合 Echarts4 实现统计图(附源码下载)

    前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...

  5. SpringCloudGateway开发详解

    路由简介: SpringCloudGateWay 是用于替代zuul作为API网关,在gateway中有三个重要的名词:过滤器,断言,路由 过滤器与断言是路由的一部分,路由便是将请求进行一系列的处理后 ...

  6. Linux第二章-Linux常用命令

    一.Linux常用快捷键 快捷键 作用 Tab 补全文件名或者路径 Ctrl + L 清除屏幕,然后,在最上面重新显示目前光标所在的这一行的内容. Ctrl + C 终止当前进程 Ctrl + D 注 ...

  7. 发布Cocos2d-x的PC端程序

    发布Cocos2d-x的PC端程序 一.创建一个Release的项目 1.利用根目录下的解决方案生成Release.win32文件夹 2.新建一个cocos2d项目(比如解决方案名称MySolutio ...

  8. nginx基础(3)

    目录 HTTP首部 1.通用首部 2.请求首部 2.1 必有首部 2.2 条件请求首部 2.3 安全相关首部 3.响应首部 3.1 必有首部 3.2 协商首部 3.3 安全相关首部 4.实体首部 4. ...

  9. atom 在Ubuntu 18.04 上安装及基本使用

    前记: Atom 是github专门为程序员推出的一个跨平台文本编辑器.具有简洁和直观的图形用户界面,并有很多有趣的特点:支持CSS,HTML,JavaScript等网页编程语言.它支持宏,自动完成分 ...

  10. LeetCode 771: 宝石与石头 Jewels and Stones

    题目: 给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头. S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石. You're given strings ...