zoukankan      html  css  js  c++  java
  • 201871010104-陈园园《面向对象程序设计(java)》第十六周学习总结

                                                                           201871010104-陈园园《面向对象程序设计(java)》第十六周学习总结

    项目 内容
    这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/
    这个作业要求在哪里 https://www.cnblogs.com/lily-2018/p/11441372.html
    作业学习目标

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

    (2) 掌握线程概念;

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

    第一部分:总结理论知识

                        线程的组成

                        线程ID:线程标识符。

      • 当前指令指针(PC):指向要执行的指令。

        寄存器集合:存储单元寄存器的集合。

        堆栈:暂时存放数据和地址,一般用来保护断点和现场。

        线程与进程区别

        线程和进程之间的区别,我觉得可以用这个例子来看出两者的不同,进程就是一栋房子,房子住着 3 个人,线程就是住在房子里的人。进程是一个独立的个体,有自己的资源,线程是在进程里的,多个线程共享着进程的资源。

        线程状态

        我们看到 Java 源代码里面,线程状态的枚举有如下 6 个。

        public enum State {
        
         //新建状态
         NEW,
        
         //运行状态
         RUNNABLE,
        
         //阻塞状态
         BLOCKED,
        
         //等待状态
         WAITING,
        
         //等待状态(区别在于这个有等待的时间)
         TIMED_WAITING,
        
         //终止状态
         TERMINATED;
        }
        

        下面给这 6 个状态一一做下解释。

        NEW:新建状态。在创建完 Thread ,还没执行 start() 之前,线程的状态一直是 NEW。可以说这个时候还没有真正的一个线程映射着,只是一个对象。

        RUNNABLE:运行状态。线程对象调用 start() 之后,就进入 RUNNABLE 状态,该状态说明在 JVM 中有一个真实的线程存在。

        BLOCKED:阻塞状态。线程在等待锁的释放,也就是等待获取 monitor 锁。

        WAITING:等待状态。线程在这个状态的时候,不会被分配 CPU,而且需要被显示地唤醒,否则会一直等待下去。

        TIMED_WAITING:超时等待状态。这个状态的线程也一样不会被分配 CPU,但是它不会无限等待下去,有时间限制,时间一到就停止等待。

        TERMINATED:终止状态。线程执行完成结束,但不代表这个对象已经没有了,对象可能还是存在的,只是线程不存在了。

        线程既然有这么多个状态,那肯定就有状态机,也就是在什么情况下 A 状态会变成 B 状态。下面就来简单描述一下。

        结合下图,我们 new 出线程类的时候,就是 NEW 状态,调用 start() 方法,就进入了 RUNNABLE 状态,这时如果触发等待,则进入了 WAITING 状态,如果触发超时等待,则进入 TIMED_WAITING 状态,当访问需要同步的资源时,则只有一个线程能访问,其他线程就进入 BLOCKED 状态,当线程执行完后,进入 TERMINATED 状态。

        线程的组成

        线程ID:线程标识符。

        当前指令指针(PC):指向要执行的指令。

        寄存器集合:存储单元寄存器的集合。

        堆栈:暂时存放数据和地址,一般用来保护断点和现场。

        线程与进程区别

        线程和进程之间的区别,我觉得可以用这个例子来看出两者的不同,进程就是一栋房子,房子住着 3 个人,线程就是住在房子里的人。进程是一个独立的个体,有自己的资源,线程是在进程里的,多个线程共享着进程的资源。

        线程状态

        我们看到 Java 源代码里面,线程状态的枚举有如下 6 个。

        public enum State {
        
         //新建状态
         NEW,
        
         //运行状态
         RUNNABLE,
        
         //阻塞状态
         BLOCKED,
        
         //等待状态
         WAITING,
        
         //等待状态(区别在于这个有等待的时间)
         TIMED_WAITING,
        
         //终止状态
         TERMINATED;
        }
        

        下面给这 6 个状态一一做下解释。

        NEW:新建状态。在创建完 Thread ,还没执行 start() 之前,线程的状态一直是 NEW。可以说这个时候还没有真正的一个线程映射着,只是一个对象。

        RUNNABLE:运行状态。线程对象调用 start() 之后,就进入 RUNNABLE 状态,该状态说明在 JVM 中有一个真实的线程存在。

        BLOCKED:阻塞状态。线程在等待锁的释放,也就是等待获取 monitor 锁。

        WAITING:等待状态。线程在这个状态的时候,不会被分配 CPU,而且需要被显示地唤醒,否则会一直等待下去。

        TIMED_WAITING:超时等待状态。这个状态的线程也一样不会被分配 CPU,但是它不会无限等待下去,有时间限制,时间一到就停止等待。

        TERMINATED:终止状态。线程执行完成结束,但不代表这个对象已经没有了,对象可能还是存在的,只是线程不存在了。

        线程既然有这么多个状态,那肯定就有状态机,也就是在什么情况下 A 状态会变成 B 状态。下面就来简单描述一下。

        结合下图,我们 new 出线程类的时候,就是 NEW 状态,调用 start() 方法,就进入了 RUNNABLE 状态,这时如果触发等待,则进入了 WAITING 状态,如果触发超时等待,则进入 TIMED_WAITING 状态,当访问需要同步的资源时,则只有一个线程能访问,其他线程就进入 BLOCKED 状态,当线程执行完后,进入 TERMINATED 状态。 

     Java 中如何创建一个线程

    继承 Thread 类,重写 run() 方法。

    class MyThread extends Thread {
    
        @Override
        public void run() {
            System.out.println("MyThread");
        }
    
    }

    实现 Runnable 接口,实现 run() 方法。

    class MyRunnable implements Runnable {
    
        public void run() {
            System.out.println("MyRunnable");
        }
    
    }
    

      这 2 种线程的启动方式也不一样。MyThread 是一个线程类,所以可以直接 new 出一个对象出来,接着调用 start() 方法来启动线程;而 MyRunnable 只是一个普通的类,需要 new 出线程基类 Thread 对象,将 MyRunnable 对象传进去。

    线程在Running的过程中可能会遇到阻塞(Blocked)情况:

    • 调用join()sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。
    • 调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable)
    • 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。

    1.实现Runnable接口,重载run(),无返回值,Runnable接口的存在主要是为了解决Java中不允许多继承的问题。

    2.继承Thread类,重写run(),通过调用Thread的start()会调用创建线程的run(),不同线程的run方法里面的代码交替执行。但由于Java不支持多继承.因此继承Thread类就代表这个子类不能继承其他类.

      • 同步:synchronized,同步的概念就是共享,只需要针对共享的资源,才需要考虑同步。

     线程同步,是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。

    线程中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理。

    三个中断方法:

    1、interrupt()

    2、isInterrupted():方法唯一的作用只是测试线程是否已经中断。

    3、interrupted():方法的作用是测试当前线程是否已经中断,线程的中断标识位由该方法清除。

    线程终止:

    1、使用 volatile 关键字修饰 变量的方式终止

    2、使用 interrupt() 方式终止

    3、Stop 方法终止

    可以直接使用thread.stop()来强行终止线程,但是stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果。

    线程处于阻塞状态
    线程处于阻塞状态,如使用了sleep,同步锁的wait,socket中的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,会抛出InterruptException异常。阻塞中的那个方法抛出这个异常,通过代码捕获该异常,然后break跳出循环状态,从而让我们有机会结束这个线程的执行。

    第二部分:实验测试

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

    测试程序1

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

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

    掌握创建JAR文件的方法;

    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");//URL来指向about.gif资源地址
          Image img = new ImageIcon(aboutURL).getImage();//利用about.gif图像文件制作图标,在找到ResourceTest类的地方查找about.gif文件
          setIconImage(img);
    
          JTextArea textArea = new JTextArea();//创建文本区
          InputStream stream = getClass().getResourceAsStream("about.txt");//读取about.txt文件
          try (Scanner in = new Scanner(stream, "UTF-8"))
          {
             while (in.hasNext())
                textArea.append(in.nextLine() + "
    ");
          }
          add(textArea);
       }
    }

    运行结果:

    测试程序2:

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

    2) 掌握线程概念;

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

    4)利用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();
         }
    }
    

     运行结果:

     

    测试程序3:

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

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

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

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

    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 JPanel
    {
       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 component.
        * @param b the ball to add
        */
       public void add(Ball b)
       {
          balls.add(b);
       }
    
       public void paintComponent(Graphics g)
       {
          super.paintComponent(g); // 擦除背景
          Graphics2D g2 = (Graphics2D) g;
          for (Ball b : balls)
          {
             g2.fill(b.getShape());
          }
       }
       
       public Dimension getPreferredSize() 
      { 
           return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
    }
    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);//使用边框布局管理器使其显示在窗口下方位置
          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)
          {
          }
       }
    }
    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;
    
       /**
        * 将球移动到下一个位置,如果球碰到其中一条边,则反向移动
        */
       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);
       }
    }
    

      运行结果:

    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 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();//调用Thread类中的start方法
       }
    }
    

      运行结果:

    实验总结:

          在上节课的基础之上,又了解了一些新的知识,学习了并发,线程的创建,中断线程,线程与进程的区别,以及多线程问题等。除了之前了解的一些基础代码之外,又学会了很多其他新的代码知识以及所表示的不同含义与用法。后一节课在老师的讲解下学习了同步。java就这样学完了,以后慢慢回顾反思。

  • 相关阅读:
    第二章 信息的表示和处理(下)
    第二章 信息的表示和处理
    IDEA中新建子模块
    手动实现一个可重入锁
    Lock接口的认识和使用
    JDK提供的原子类原理与使用
    深入理解volatile原理与使用
    模拟死锁
    模拟自旋锁
    grep 如何自动标注颜色
  • 原文地址:https://www.cnblogs.com/chanyeol1127/p/12034363.html
Copyright © 2011-2022 走看看