线程使用介绍和应用(运动的小球)

先看一下效果:

提取码5vub

一、简单介绍


以下介绍来自csdn博主菜鸟LV1的文章


1.进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。

2.线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。

一个程序至少一个进程,一个进程至少一个线程。

①地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。

②资源拥有:同一进程内的线程共享本进程的资源,但是进程之间的资源是独立的。

③一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

④进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。

⑤执行过程:每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

线程是处理器调度的基本单位,但是进程不是。

⑦两者均可并发执行。

3.优缺点:

①线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。

②进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。

4.什么地方用到多线程?

后台线程:比如定期执行一些特殊任务,如定期更新配置文件,任务调度,一些监控用于定期信息采集等。

②最典型的应用比如tomcat,tomcat内部采用的就是多线程,上百个客户端访问同一个web应用,tomcat接入后都是把后续的处理扔给一个新的线程来处理,这个新的线程最后调用到我们的servlet程序,比如doGet或者doPost方法。还有就是需要异步处理的时候,需要使用多线程。

特别耗时的操作,如备份数据库,可以开个线程执行备份,然后执行返回,前台不断向后台询问线程执行状态。

5.多线程实现方法

①继承Thread类

②实现Runnable接口

一个类如果实现了Runnable接口或者继承了Thread类,那么它就是一个多线程类,如果是要实现多线程,还需要重写run()方法,所以run() 方法是多线程的入口。

区别:

  • Thread是Runnable接口的子类,实现Runnable接口的方式解决了Java单继承的局限
  • Runnable接口实现多线程比继承Thread类更加能描述数据共享的概念

 

6.多线程有几种实现同步方法?
同步的实现方面有两种,分别是synchronized,wait与notify

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

7.产生死锁的原因?
产生死锁的四个必要条件:

1、互斥条件:一个资源每次只能被一个进程使用。

2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁
上面列出了死锁的四个必要条件,我们只要想办法破其中的任意一个或多个条件,就可以避免死锁发生,一般有以下几种方法:

1、按同一顺序访问对象。

2、避免事务中的用户交互。

3、保持事务简短并处于一个批处理中。

4、使用较低的隔离级别。

5、使用基于行版本控制的隔离级别。

6、使用绑定连接。


二、项目示实例

1.功能:

①界面

②界面上运动的小球

③小球间相互独立,小球之间、小球与界面边界碰撞满足动量定理

2.基本框架:

  • 小球彼此之间相互独立,它们的活动是同时发生的
  • 小球之间会发生碰撞,需要互相知晓彼此的位置信息,因此共享一份信息
  • Frame上运动着多个ball,Frame管理它们的活动和信息
  • 可将Frame作为进程,每产生一个小球,生成一个线程来进行管理。

因此Frame是爸爸(进程),家里每多一个宝宝(ball),爸爸就请一个保姆(线程)来看管,爸爸会给保姆安排一些基本的工作和对宝宝的各种活动的处理方式,爸爸掌握着所有宝宝的活动和情况和信息。

3.具体实现

①宝宝(ball)的基本活动和信息

信息:颜色,运动方向,速度,位置

活动:运动,在爸爸(进程)的房子里(Frame)按照速度方向、大小运动

②管家(run)处理的事件和方式

在接收到爸爸(进程)的start()命令后,开始和宝宝活动,接收到爸爸的暂停命令后,立即阻止宝宝的运动(stop)

宝宝(ball)可能撞到墙上(边界),还可能和别的宝宝(ball)撞到一起,聪明的管家根据动量守恒定律改变宝宝的运动状态。

 

4.代码实现

①Ball类:

  • 构造函数内颜色和大小随机生成
  • 在给定的位置开始运动,速度随机生成
  • 小球需要画出自己,要制造出运动的效果,联想到动画片,就是利用视觉暂留将一张一张的图片连续展示的结果:

          ①我们必须让小球不断变化位置,每次用给定的颜色画小球之前用背景颜色把之前的小球擦除,保证任何时刻一个Ball只显示一个球的图像

          ②在每一个图像上需要停留一段时间,这里设置的是100ms,用的是sleep函数让线程休眠。

  • 小球要有判断自己是否撞到边界或者其他的球的方法,并且在这些方法里面做出响应反应

   ①如果撞到边界,让相应方向的“速度”(dx/dy)反向。

   ②如果撞到其他小球,交换两个小球的速度(如果严格按照动量守恒定律,速度的变化会要复杂一些)。

  • 每个小球地运动是独立地,因此我们在这里实现Runnable接口,运用线程来实现,那么就需要重写它里面的run函数
  • 最重要的一个函数,是run函数,线程启动后执行的就是run方法,需要并行实现独立的功能必须在run里面实现或者呗调用:

  小球独立地运动,因此重复进行三个过程:①位置移动 ②判断撞击的情况并作出处理  ③画出小球 ④暂留一段时间后擦去小球

package Ball_thread_5_20;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class Ball implements Runnable{
	private Ball []ball_array= new Ball[100];//引用进程的100个线程
	public int num,width,height,x,y,dx,dy;
	private Color color;
	private int r;
	private Graphics g;//画布
	Random random=new Random();

	//重写run函数,运动
	public void run(){
		while(true){
			x+=dx;y+=dy;
			//撞到边界
			overEdge();
			//与其他小球碰撞
			Ball temp;
			for(int i=0;i<num;i++){
				temp=ball_array[i];
				if(temp!=this){
					temp.crash(this);
				}
			}
			this.drawBall();
			this.cleanBall();
		}
	}
	
	//构造函数
	public Ball(int x,int y,int r,int w,int h){
		this.x=x;
		this.y=y;
		this.r=random.nextInt(r)+20;
		//界面的高度和宽度
		width=w;
		height=h;
		//随机生成速度向量
		dx=random.nextInt(60)-30;
		dy=random.nextInt(60)-30;
		//随机生成颜色
		int c1,c2,c3;
		c1=random.nextInt(255);
		c2=random.nextInt(255);
		c3=random.nextInt(255);
		color=new Color(c1,c2,c3);
	}
	
	//获得画布
	public void setg(Graphics g){
		this.g=g;
	}
	
	//获得小球数组
	public void setBalls(Ball[] b,int num){
		ball_array=b;
		this.num=num;
	}
	
	//判断是否超出边界
	public void overEdge(){
		if(x+r>width){
			x=width-r;
			dx=-dx;
		}
		if(y+r>height){
			y=height-r;
			dy=-dy;
		}
		if(x-r<0){
			x=r;
			dx=-dx;
		}
		if(y-r<0){
			y=r;
			dy=-dy;
		}
	}
	
	//判断是否和x,y处的球相撞
	public void crash(Ball b){
		int i=b.x,j=b.y;
		if((i-x)*(i-x)+(j-y)*(j-y)<=r*r){
			int temp1=b.dx,temp2=b.dy;
			b.dx=this.dx;this.dx=temp1;
			b.dy=this.dy;this.dy=temp2;
			if(b.x<this.x)	b.x=this.x-2*r;
			else		    b.x=this.x+2*r;
			if(b.y<this.y)  b.y=this.y-2*r;
			else            b.y=this.y+2*r;
			
		}
	}
	
	//画出小球
	public void drawBall(){
		g.setColor(color);
		g.fillOval(x, y, r, r);
	}

	//擦除小球
	public void cleanBall(){
		//线程休眠100ms
		try{
			Thread.sleep(100);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		g.setColor(new Color(240,240,240));
		g.fillOval(x, y, r, r);
	}
	

}

②BallUI类(界面):

  • 界面类首先功能必须能展示一个界面,在init方法中初始化一个界面并获得画布(因为小球需要画出来)
  • 我们要实现的是界面上在鼠标点击处生成一个小球,所以需要监听鼠标点击事件,(在初始化界面的时候需要添加鼠标监听器也就是this),实现MouseListner接口,重写其中的Mouseclicked函数来处理鼠标点击事件:

①得到点击位置并生成小球,将小球加入集合,将界面的画布传给小球,以便画画

       ②创建线程Thread对象,启动线程

package Ball_thread_5_20;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;

public class BallUI extends JFrame implements MouseListener{
	/**
	 * 继承JFrame,实现鼠标监听器接口
	 */
	private static final long serialVersionUID = 1L;
	private Ball []ball_array= new Ball[100];//最多100个ball
	private Graphics g ;//画布
	private BallUI UI;//窗口对象
	private int num,r=20;//小球个数
	
	//主函数
	public static void main(String[] args){
		BallUI bui=new BallUI();
		bui.init();
	}
	
	@Override
	public void paint(Graphics g) {
		super.paint(g);
//		drawBall(g);
//		moveBall();

	}
	
	//显示界面
	public void init(){
		num=0;
		UI=this;
		this.setTitle("willow's balls~");
		this.getContentPane().setBackground(new Color(240,240,240));
		this.setSize(1000, 600);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
		//添加监听器
		this.addMouseListener(this);
		g=this.getGraphics();//获得画布
	}
	
	
	//实现接口函数鼠标点击,响应点击事件
	@Override
	public void mouseClicked(MouseEvent arg0) {
		//在(x,y)生成新的小球并加入小球集合ball_array
		int x=arg0.getX(),y=arg0.getY();
		Ball b=new Ball(x,y,r,UI.getWidth(),UI.getHeight());
		b.setBalls(ball_array,num);
		b.setg(g);
		ball_array[num++]=b;
		//启动小球线程
		Thread t = new Thread(b);
		t.start();
	}


	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
}

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hnu哈哈

请接受直女的么么哒????

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值