201871010105-曹玉中《面向对象程序设计(java)》第十六周学习总结

201871010105-曹玉中《面向对象程序设计(java)》第十六周学习总结

项目 内容
这个作业属于哪个过程 https://www.cnblogs.com/nwnu-daizh/
这个作业的要求在哪里 https://www.cnblogs.com/zyja/p/11963340.html
作业学习目标

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

(2) 掌握线程概念;

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

第一部分:理论知识。

进程:指一个内存中运行的应用程序。例如运行QQ那么它就是一个进程,而且一个应用程序可以同时运行多个进程

线程:线程是进程中的一个执行单元,就比如用360我们可以让它一边杀毒一边清理垃圾,那么360它就是一个进程,那么杀毒和清理垃圾就是进程下的两个线程
注:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

Thread类
构造方法:
public Thread() :分配一个新的线程对象。

public Thread(String name) :分配一个指定名字的新的线程对象。

public Thread(Runnable target) :分配一个带有指定目标新的线程对象。

public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

常用方法:
public String getName() :获取当前线程名称。

public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

public void run() :此线程要执行的任务在此处定义代码。

public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停

public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

创建线程的方式总共有两种:
1.是继承Thread类方式
2.是实现Runnable接口

创建线程的方式一:

定义Thread类子类,并重写该类的run()方法,run()方法的方法体就代表了线程需要完成的任务,
创建Thread子类的实例3. 调用Thread的start()方法来启动该线程
代码如下:

public class Test {
public static void main(String[] args) {
MyThread mt = new MyThread();
Thread t1 = new Thread(mt);    
t1.start();    
}
}
class MyThread extends Thread{
@Override
public void run(){
System.out.println("第一种方式创建线程");    
}
}

创建线程的方式二:

定义Runnable接口的实现类,并重写该接口的run()方法,run()方法的方法体代表线程完成的任务
创建Runnable实现类的实例。
调用Thread的start()方法来启动线程。
代码如下:

public class Test {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr);
t1.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("第二种方式创建线程");    
}
}

Thread和Runnable的区别
因为类都是单继承的,如果一个类继承Thread,就不可以继承其他类了。但是如果实现了Runnable接口的话,则很容易的实现资源共享,避免了java中的单继承的局限性,所以Runnable比Thread更有优势

用匿名内部类创建线程
使用匿名内部类的方式实现Runnable接口,重写Runnable接口中的run方法:

代码如下:

public class Test {
public static void main(String[] args) {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("匿名内部类创建线程");
}
}).start();
}
}

线程安全问题的概述
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
那么什么是线程不安全的呢?我们由一段代码看一下:
这里我想打印的是1-100之间的整数:

public class Test {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
t1.start();
t2.start();
t3.start(); 
}
}
class MyRunnable implements Runnable{
private int sum = 100;
public void run(){
while(true){
if(sum>0){
try {
Thread.sleep(10);
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sum);
sum--;
}
}
}
}

运行结果出现了很多重复的,甚至还有-1,结果和预期是不一样的,这就是线程不安全情况。那么为什么会出现这种情况呢?是因为这三个线程在执行过程中不断抢夺CPU的执行权,当某一个线程运行到Thread.sleep(10)的时候处于睡眠状态,那么CPU的执行权交给了另外两个线程以此类推,三个线程都执行到了这里,这时代码就不是一条判断一条输出了,当睡眠结束后三条线程面临的都是一条输出语句一个sum–不再判断sum的值,若最后判断sum的值为1,最后sum的值将被–三次,所以才会导致最终的结果出现0和-1的情况(最终sum的值为-2),这里的Thread.sleep()其实是为了增加线程安全问题出现的概率。
第二部分:实验。

测试程序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);
      });
   }
}

/**
 * A frame that loads image and text resources.
 */
class ResourceTestFrame extends JFrame
{
   private static final int DEFAULT_WIDTH = 300;
   private static final int DEFAULT_HEIGHT = 300;

   public ResourceTestFrame()
   {
      setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
      URL aboutURL = getClass().getResource("about.gif");
      Image img = new ImageIcon(aboutURL).getImage();
      setIconImage(img);

      JTextArea textArea = new JTextArea();
      InputStream stream = getClass().getResourceAsStream("about.txt");
      try (Scanner in = new Scanner(stream, "UTF-8"))
      {
         while (in.hasNext())
            textArea.append(in.nextLine() + "\n");
      }
      add(textArea);
   }
}
Main-Class: resource.ResourceTest

Core Java: Fundamentals
10th Edition
Cay Horstmann and Gary Cornell
Copyright 漏 2016
Prentice-Hall

 

 

运行结果如下:

 

 

 

测试程序2:

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

l 掌握线程概念;

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

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

代码如下:

class Lefthand extends Thread { 
   public void run()
   {
       for(int i=0;i<=5;i++)
       {  System.out.println("You are Students!");
           try{   sleep(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);  }
             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();
     }
}

 

运行结果如下:

 

 Runnable接口创建线程的方法

class Lefthand implements Runnable {
    public void run() {
        for (int i = 0; i <= 5; i++) {
            System.out.println("You are Students!");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println("Lefthand error.");
            }
        }
    }
}

class Righthand implements Runnable {
    public void run() {
        for (int i = 0; i <= 5; i++) {
            System.out.println("I am a Teacher!");
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                System.out.println("Righthand error.");
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        Runnable left = new Lefthand();
        Thread a = new Thread(left);
        Runnable right = new Righthand();
        Thread b = new Thread(right);
        a.start();
        b.start();
    }
}

运行结果如下:

 

 

测试程序3:

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

代码如下:

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.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 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());//将按钮放入buttonPanel
      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());
            comp.paint(comp.getGraphics());
            Thread.sleep(DELAY);//在两个球显示之间有延迟
         }
      }
      catch (InterruptedException e)//中断异常
      {
      }
   }
}

Bounce

Bounce

 

 

运行结果如下:

 

 

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

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

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

代码如下:

package bounceThread;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

/**
 * 显示动画弹跳球
 * @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);
        });
    }
}

/**
 * 框架与球组件和按钮
 */
class BounceFrame extends JFrame {
    private BallComponent comp;
    public static final int STEPS = 1000;
    public static final int DELAY = 5;

    /**
     * 用显示弹跳球以及开始和关闭按钮的组件构建框架
     */
    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();
    }

    /**
     * 向容器添加按钮
     * 
     * @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);
    }

    /**
     * 在画布上添加一个弹跳球,并启动一个线程使其弹跳
     */
    public void addBall() {
        Ball ball = new Ball();
        comp.add(ball);
        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);
        t.start();
    }
}

 

运行结果如下:

 

 

第三部分:学习总结

 

   通过本章的学习,掌握了一些关于线程的相关知识,在学习的时候学的一片混乱,好在课下通过看书

和在Mooc上 看翁凯老师的课才对本章内容有了一定的了解,但还需要再做一些练习才能够掌握本章内容

的精髓,在做验证性实验部分内容的时候,并没有遇到很多困难,同时体验到了本章实验内容的重要性,

但实验课的时候遇到较多问题,好在在助教学长的帮助下得以解决,我也会在课下多多学习,加强巩固

基础知识。

posted on 2019-12-18 20:26  曹玉中-201871010105  阅读(197)  评论(1编辑  收藏  举报