201871010112-梁丽珍《面向对象程序设计(java)》第十六周学习总结

时间:2019-12-18
本文章向大家介绍201871010112-梁丽珍《面向对象程序设计(java)》第十六周学习总结,主要包括201871010112-梁丽珍《面向对象程序设计(java)》第十六周学习总结使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

项目

内容

这个作业属于哪个课程

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

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

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

掌握创建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

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

掌握线程概念;

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

利用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

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

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

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

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

程序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()接口实现线程;理解和掌握了线程的优先级属性及调度方法,学到了线程的七种状态。

原文地址:https://www.cnblogs.com/LZ-728672/p/12041139.html