当前位置: 首页 > news >正文

暑假集训篇之并发处理①练习题

一、练习题解析+代码

 ①用一个线程控制面板上多个移动的小球

思路:

多个小球它们属于小球类,并且具备的属性特征相同,此时如果要一个线程控制所有的小球,则需要将所有的小球放在一个数组中记录下来,而且众多小球的属性应用一个小球类表示,用构造方法进行属性的初始化,将小球位置用List储存,小球运动前要画出小球。为了保证线程只启动一个,那么需要考虑的是线程所在的方法只能调用一次,只有构造方法才会只调用一次,所以把线程启动放在构造方法中。为了确保不会二次调用再加上一个条件判断

代码如下:

package daytoday25.lfx0720;import javax.swing.*;
import java.awt.*;public class ThreadUI {public void initUI(){JFrame jf=new JFrame();jf.setTitle("多线程");jf.setSize(900,900);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setLocationRelativeTo(null);JPanel jp = new JPanel();jp.setBackground(Color.WHITE);jf.add(jp,BorderLayout.CENTER);jf.setVisible( true);//从窗体上获得画笔Graphics g = jp.getGraphics();//监听器ThreadListener tl = new ThreadListener(g);jp.addMouseListener(tl);}public static void main(String[] args) {ThreadUI ui = new ThreadUI();ui.initUI();}
}
package daytoday25.lfx0720;import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;public class ThreadListener extends MouseAdapter {public Graphics g;//我们如果用一条线程来操控所有的小球 此时就需要将所有的小球位置都记录下来public ArrayList<Ball> balls = new ArrayList<>();public ThreadBall threadBall;//构造方法初始化属性 [很多属性在使用的时候首先要初始化]public ThreadListener(Graphics g){this.g = g;if (threadBall == null) {//创建线程对象threadBall = new ThreadBall(g, balls);//启动线程threadBall.start();}}public void mouseClicked(MouseEvent e){int x = e.getX();int y = e.getY();//创建小球对象Ball ball = new Ball(x, y);balls.add(ball);}}
package daytoday25.lfx0720;import java.awt.*;
import java.util.ArrayList;public class ThreadBall extends Thread{//run Thread 类 实现了Runable 接口的run方法public Graphics  g;public ArrayList<Ball> balls;//构造方法初始化属性public ThreadBall(Graphics g,ArrayList<Ball> balls) {this.g = g;this.balls = balls;}//run 方法是启动线程后自动执行的方法//该方法执行完,当前线程的所有资源都会被回收@Overridepublic void run() {//重写run方法System.out.println("线程启动了");while ( true){//延长时间try {Thread.sleep(3);} catch (InterruptedException ex) {throw new RuntimeException(ex);}//取出所有的小球for (int i = 0; i < balls.size(); i++){Ball ball = balls.get(i);ball.drawBall(g);}}}
}
package daytoday25.lfx0720;import java.awt.*;public class Ball {//小球类的属性,在用构造方法初始化属性int x,y;int size;public Ball(int x, int y) {this.x = x;this.y = y;size = 50;}//画小球public void drawBall(Graphics g) {g.setColor(Color.WHITE);g.fillOval(x++, y, size, size);g.setColor(Color.BLACK);g.fillOval(x, y, size, size);}}

 ②小球在碰撞界面框的时候会发生反弹

思路:

先规定小球的速度有助于我们写小球的碰撞,之后思考小球反弹的条件,小球在面板上面运动,只有在接触到面板的边界的时候就会发生反弹。我们此时要思考如何获取面板的宽高,用静态变量在界面类中重新定义面板,之后在小球类中用类名调用面板的方法getWidth和getHeight

代码示例如下:[只出示需要改变的类的代码]

package daytoday25.lfx0720;import java.awt.*;public class Ball {//小球类的属性,在用构造方法初始化属性public int x,y;public int size;//小球的速度public int speedX,speedY;public Ball(int x, int y) {this.x = x;this.y = y;size = 50;speedX = 2;speedY = 2;}//画小球public void drawBall(Graphics g) {g.setColor(Color.WHITE);g.fillOval(x, y, size, size);x += speedX;y += speedY;g.setColor(Color.BLACK);g.fillOval(x, y, size, size);//判断是否需要反弹if (x> ThreadUI.jp.getWidth()-size || x<0|| y> ThreadUI.jp.getHeight()-size || y<0){speedX = -speedX;speedY = -speedY;}}}
package daytoday25.lfx0720;import javax.swing.*;
import java.awt.*;public class ThreadUI {//用静态变量 : 固定不变的 不管创建多少个类 静态变量都不会改变static  JPanel jp = new JPanel();public void initUI(){JFrame jf=new JFrame();jf.setTitle("多线程");jf.setSize(900,900);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setLocationRelativeTo(null);jp.setBackground(Color.WHITE);jf.add(jp,BorderLayout.CENTER);jf.setVisible( true);//从窗体上获得画笔Graphics g = jp.getGraphics();//监听器ThreadListener tl = new ThreadListener(g);jp.addMouseListener(tl);}public static void main(String[] args) {ThreadUI ui = new ThreadUI();ui.initUI();}
}

二、7.13练习

①设置暂停键

②处理小球之间碰撞的问题

代码示例:

package daytoday25.lfx0720;import javax.swing.*;
import java.awt.*;public class ThreadUI {//用静态变量 : 固定不变的 不管创建多少个类 静态变量都不会改变static  JPanel jp = new JPanel(); //面板public void initUI(){JFrame jf=new JFrame();jf.setTitle("多线程");jf.setSize(900,900);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setLocationRelativeTo(null);JPanel btnJp = new JPanel();//按钮面板btnJp.setBackground(Color.GRAY);btnJp.setPreferredSize(new Dimension(100,0));//按钮面板上添加按钮JButton btn = new JButton("暂停");btn.setBackground(Color.WHITE);btn.setPreferredSize(new Dimension(80,40));btnJp.add(btn);jp.setBackground(Color.WHITE);jf.add(jp,BorderLayout.CENTER);jf.add(btnJp,BorderLayout.EAST);jp.setFocusable(true);//使面板获得焦点jf.setVisible( true);//从窗体上获得画笔Graphics g = jp.getGraphics();jp.requestFocusInWindow();//监听器ThreadListener tl = new ThreadListener(g);jp.addMouseListener(tl);jp.addKeyListener(tl);btn.addActionListener(tl);}public static void main(String[] args) {ThreadUI ui = new ThreadUI();ui.initUI();}
}
package daytoday25.lfx0720;import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;public class ThreadListener extends MouseAdapter implements ActionListener ,KeyListener {public Graphics g;//我们如果用一条线程来操控所有的小球 此时就需要将所有的小球位置都记录下来public ArrayList<Ball> balls = new ArrayList<>();public ThreadBall threadBall;//构造方法初始化属性 [很多属性在使用的时候首先要初始化]public ThreadListener(Graphics g){this.g = g;if (threadBall == null) {//创建线程对象threadBall = new ThreadBall(g, balls);//启动线程threadBall.start();}}public void mouseClicked(MouseEvent e){int x = e.getX();int y = e.getY();//创建小球对象
//        Ball ball = new Ball(x, y);
//        balls.add(ball);/*线程安全添加作用:当多个线程同时访问这段代码块时,同一时间只能有一个线程获得balls对象的锁,进入同步代码块执行添加操作其他线程必须等待当前线程执行完同步代码块并释放锁后,才能获得锁并执行*/synchronized(balls){balls.add(new Ball(x,y));//创建小球对象}}@Overridepublic void actionPerformed(ActionEvent e) {String ac = e.getActionCommand();if (ac.equals("暂停")){threadBall.setRunning(false);JButton btn = (JButton) e.getSource();btn.setText("继续");btn.setBackground(Color.GREEN);} else if (ac.equals("继续")) {threadBall.setRunning(true);JButton btn = (JButton) e.getSource();btn.setText("暂停");btn.setBackground(Color.WHITE);}}/*KeyListener工作机制要求:1、监听的组件必须可获得焦点(默认情况下 JPanel不可获得焦点)2、该组件必须当前拥有焦点(即用户通过点击或代码设置使其成为焦点组件)*///有字符输出时,方法就会触发@Overridepublic void keyTyped(KeyEvent e) {}//当某个按键按下,该方法就会触发@Overridepublic void keyPressed(KeyEvent e) {
//        System.out.println( (char) e.getKeyChar() + "被按下……");if (e.getKeyCode() == KeyEvent.VK_DOWN){// KeyEvent.VK_DOWN就是向下的箭头}}//当某个按键释放,该方法就会触发@Overridepublic void keyReleased(KeyEvent e) {}
}
package daytoday25.lfx0720;import java.awt.*;
import java.util.ArrayList;public class ThreadBall extends Thread{//run Thread 类 实现了Runable 接口的run方法public Graphics  g;public ArrayList<Ball> balls;private  volatile boolean running = true;//构造方法初始化属性public ThreadBall(Graphics g,ArrayList<Ball> balls) {this.g = g;this.balls = balls;}/*构造一个setRunning方法 来设置线程运行状态*/public void setRunning(boolean running) {this.running = running; //设置线程运行状态}//run 方法是启动线程后自动执行的方法//该方法执行完,当前线程的所有资源都会被回收@Overridepublic void run() {//重写run方法// System.out.println("线程启动了");while ( true){if (running == true){//获取面板尺寸int width = ThreadUI.jp.getWidth();int height = ThreadUI.jp.getHeight();//清空画布 用白色填充整个画面g.setColor(Color.WHITE);g.fillRect(0,0,width,height);//绘制并更新小球synchronized (balls){//以balls对象作为锁来创建同步代码块//遍历 检测所有小球间的碰撞  利用双层for循环可以避免重复检测for (int i = 0;i < balls.size();i++){Ball ball1 = balls.get(i);for (int j = i+1;j < balls.size();j++){Ball ball2 = balls.get(j);if (ball1.isCollisionWith(ball2)){ball1.handleCollisionWith(ball2);}}}for (Ball ball : balls){//遍历balls中的所有的小球ball.drawBall(g);//绘制小球}}}//延长时间try {Thread.sleep(3);//线程休眠3毫秒 控制动画刷新率约 3帧/秒} catch (InterruptedException ex) {throw new RuntimeException(ex);}//取出所有的小球
//            for (int i = 0; i < balls.size(); i++){
//                Ball ball = balls.get(i);
//                ball.drawBall(g);
//            }}}
}
package daytoday25.lfx0720;import java.awt.*;public class Ball {//小球类的属性,在用构造方法初始化属性public int x,y;public int size;//小球的速度public int speedX,speedY;public Ball(int x, int y) {this.x = x;this.y = y;size = 50;speedX = 2;speedY = 2;}//画小球public void drawBall(Graphics g) {g.setColor(Color.WHITE);g.fillOval(x, y, size, size);x += speedX;y += speedY;g.setColor(Color.BLACK);g.fillOval(x, y, size, size);//判断是否需要反弹
//        if (x> ThreadUI.jp.getWidth()-size || x<0|| y> ThreadUI.jp.getHeight()-size || y<0){
//            speedX = -speedX;
//            speedY = -speedY;
//
//        }checkBoundaryCollision();}//小球反弹方法public void checkBoundaryCollision(){if (x> ThreadUI.jp.getWidth()-size || x<0|| y> ThreadUI.jp.getHeight()-size || y<0){speedX = -speedX;speedY = -speedY;}}//小球之间碰撞的方法public boolean isCollisionWith(Ball other){//计算两个小球中心距离的平方int dx = (x + size / 2) - (other.x + size / 2);int dy = (y + size / 2) - (other.y + size / 2);int distance = dx * dx + dy * dy;//小球直径的平方int dsum =  size*size;return distance < dsum;//如果两球中心距离的平方小于小球直径的平方,则两球发生碰撞}//处理两球之间的碰撞public void handleCollisionWith(Ball other){speedX = -speedX;speedY = -speedY;other.speedX = -other.speedX;other.speedY = -other.speedY;}}

大体思路:

暂停:

1、添加按钮面板添加上按钮并在按钮上添加动作监听器

2、按钮文本的变换在暑假篇中有提及

3、实现按钮功能,在ThreadBall中用画布对原来的面板进行覆盖,将记录的小球最终位置重绘在画布上面

小球碰撞:

1、小球碰撞的条件是两小球中心坐标距离的平方等于一个小球直径的平方,当这个条件触发的时候就可以发生碰撞并且反弹【这里只说最简单的完全非弹性碰撞】

2、在ball类中写完碰撞条件,此时就要对所有的小球进行检测,双层for循环检测小球之间的碰撞

http://www.lryc.cn/news/598952.html

相关文章:

  • C语言转义字符‘\\‘‘ 解析与常见误区
  • SAP全自动化工具开发:Excel自动上传与邮件通知系统
  • Python字典get方法使用解析
  • Spring之SSM整合流程详解(Spring+SpringMVC+MyBatis)
  • Windows上用于跨平台开发的环境工具
  • 数据集成难在哪?制造企业该怎么做?
  • 神经网络实战案例:用户情感分析模型
  • DPO:大语言模型偏好学习的高效方案
  • 平时遇到的错误码及场景?404?400?502?都是什么场景下什么含义,该怎么做 ?
  • 前端性能新纪元:Rust + WebAssembly 如何在浏览器中实现10倍性能提升(以视频处理为例)
  • Linux 磁盘挂载,查看uuid
  • OpenCV图像插值、边缘填充、图像掩膜、噪声消除实战指南
  • Effective Python 第16条:用get处理字典缺失键,避免in与KeyError的陷阱
  • 100条SQL语句分类精讲:从基础到进阶的实操指南
  • OpenGL绘制正方形、错误处理、统一变量、索引缓冲区
  • tcp基础协议
  • node.js中的path模块
  • MySQL深度理解-MySQL索引优化
  • AI服务器给一体成型电感带来多大的市场空间
  • Java学习日记_廖万忠
  • 深度解析:在Odoo 18中基于原生Owl框架为PWA定制功能丰富的底部导航栏
  • 面经 - 车载多媒体系统
  • Vue2——5
  • [CH582M入门第十一步]DS18B20驱动
  • 金仓数据库:从国产替代到AI融合的破局之路
  • Mysql窗口函数
  • 2025年海外短剧独立站开发:H5+PC端双平台技术实践与增长策略
  • 《AI流程编排中的Graph观测:设计原理与集成实践》
  • 高并发系统设计面试题
  • 深度分析Java多线程机制