Java线程系列(一)线程无返回值的两种实现方式

情景导入

在程序执行的过程中,如果遇见for循环,一般情况下需要该循环结束后,程序才会开始执行下一条指令;而我们平时在使用电脑时却可以一边听音乐一边刷微博,而这,就是靠多线程来实现的。

专业名词解释

线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务(以上解释来源于百度词条)。

举例分析

画小球一般方法

public class Normal_Way extends JFrame{
	public static void main(String[] agrs) {
		new Normal_Way();
	}
	public Normal_Way() {
		// TODO Auto-generated constructor stub
		setTitle("普通圆圈");
		setSize(800,600);
		setDefaultCloseOperation(3);
		setLocationRelativeTo(null);
		setVisible(true);
		
		Graphics g=getGraphics();
		addMouseListener(new MouseAdapter() {
			 public void mouseClicked(MouseEvent e) {
				 int x=e.getX();
				 int y=e.getY();
				 
				 Oval oval=new Oval(g,x,y,Color.black);
			 }	
		});
	}
}
public class Oval {
	Graphics g;
	int x;
	int y;
	Color color;
	
	public Oval(Graphics g,int x,int y,Color color) {
		// TODO Auto-generated constructor stub
		this.g=g;
		this.x=x;
		this.y=y;
		this.color=color;
		for(int i=0;i<50;i++) {
			try {							//增大每次循环的时间间隔
				Thread.sleep(40);
			}catch (InterruptedException ex) {
				ex.printStackTrace();
			}
			g.drawOval(x+5*i, y+5*i, 40, 40);//画圆圈,并改变圆圈的位置
		}
	}
}

程序运行结果如下:
在这里插入图片描述
程序虽然运行了三次,但是每一次绘制却是在上次图形画完之后再开始的,有没有办法在第一次绘制还未完成的时候就开始第二次图形的绘制呢?
当然可以!使用线程嘛~

实现线程的方法
实现线程的方式有两类,一类是有返回值的,一类是没有返回值的,这里介绍两种没有返回值的实现方式。
1 继承Thread类,重写run()方法
First_Try.java

public class First_Try extends JFrame{
	
	public static void main(String[] args) {
		First_Try ft1=new First_Try();
	}
		public void paint(Graphics g) {	
			super.paint(g);
	}
		public First_Try() {	
			setTitle("小球一");
			setSize(800,600);
			setDefaultCloseOperation(3);
			setLocationRelativeTo(null);
			setVisible(true);
			
			Graphics g=this.getGraphics();
			
			addMouseListener (new MouseAdapter() {
				public void mousePressed(MouseEvent e){
					int x=e.getX (); 
					int y=e.getY ();
					
					Color color=Color.black;
					RunBall ballRun1 = new RunBall (g,x,y,color);
					ballRun1.start ();// 启动线程 
			}
		});
	}
}

RunBall.java

public class RunBall extends Thread{
	Graphics g;
	int x;
	int y;
	Color color;
	//构造方法
	public RunBall(Graphics g,int x,int y,Color color) {
		this.g=g;
		this.x=x;
		this.y=y;
		this.color=color;
	}
	//重写run()方法
	public void run() {
		for(int i=0;i<50;i++) {
			try {
				Thread.sleep(40);
			}catch (InterruptedException ex) {
				ex.printStackTrace();
			}
			g.setColor(color);
			g.drawOval(x+5*i, y+5*i, 50, 50);
		}
	}
}

程序运行结果如下
在这里插入图片描述
单看图片可能和上个程序没啥区别,但是这一次是能在第一次图形还未绘制完成时就可以进行第二次图形的绘制,就相当于你在用手机刷微博的同时还能听音乐。
如果多创建几个线程会是什么效果呢?
这里通过改变画笔的颜色方便观察程序运行的过程。
我们在First_Try类中添加以下代码:

		color=Color.red;
		RunBall ballRun2 = new RunBall (g,x,y,color);
		ballRun2.start ();// 启动线程 
					
		color=Color.blue;
		RunBall ballRun3 = new RunBall (g,x,y,color);
		ballRun3.start ();//启动线程

程序运行效果如下:
在这里插入图片描述
2实现Runable接口,重写run方法
Second_Try.java

public class Second_Try extends JFrame{

	public static void main(String[] args) {
		new Second_Try();
	}
	
	public Second_Try() {
		// TODO Auto-generated constructor stub
		setTitle("小球二");
		setSize(800,600);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		
		Graphics g=this.getGraphics();
		
		addMouseListener (new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				int x=e.getX();
				int y=e.getY();
				
			//	g.setColor(Color.blue);
				RunBall2 ball1=new RunBall2(g,x,y,Color.blue);
				new Thread(ball1).start();;
				
			//	g.setColor(Color.red);
				RunBall2 ball2=new RunBall2(g,x,y,Color.red);
				new Thread(ball2).start();
				
			//  g.setColor(Color.yellow);	
				RunBall2 ball3=new RunBall2(g,x,y,Color.yellow);
				new Thread(ball3).start();
			}
		});		
	}
	public void paint(Graphics g) {
		super.paint(g);
	}	
}

RunBall2.java

public class RunBall2 implements Runnable{
	Graphics g;
	int x;
	int y;
	Color color;
	public RunBall2(Graphics g,int x,int y,Color color) {
		// TODO Auto-generated constructor stub
		this.g=g;
		this.x=x;
		this.y=y;
		this.color=color;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<50;i++) {
			try {
				Thread.sleep(40);
			}catch (InterruptedException ex) {
				ex.printStackTrace();
			}
			g.setColor(color);
			g.drawOval(x+5*i, y+5*i, 40, 40);
		}	
	}
}

程序运行如下:
在这里插入图片描述

BUG解决

在实现线程的过程中可能会遇到颜色覆盖的问题。
请问以下程序能否实现上述效果:

public class Second_Try extends JFrame{
	public static void main(String[] args) {
		new Second_Try();
	}
	public Second_Try() {
		// TODO Auto-generated constructor stub
		setTitle("小球二");
		setSize(800,600);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		
		Graphics g=this.getGraphics();
		
		addMouseListener (new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				int x=e.getX();
				int y=e.getY();
				
				g.setColor(Color.blue);//新增
				RunBall2 ball1=new RunBall2(g,x,y,Color.blue);
				new Thread(ball1).start();;
				
				g.setColor(Color.red);//新增
				RunBall2 ball2=new RunBall2(g,x,y,Color.red);
				new Thread(ball2).start();
				
				g.setColor(Color.yellow);//新增
				RunBall2 ball3=new RunBall2(g,x,y,Color.yellow);
				new Thread(ball3).start();
			}
		});	
	}
	public void paint(Graphics g) {
		super.paint(g);
	}	
}
public class RunBall2 implements Runnable{
	Graphics g;
	int x;
	int y;
	Color color;
	public RunBall2(Graphics g,int x,int y,Color color) {
		// TODO Auto-generated constructor stub
		this.g=g;
		this.x=x;
		this.y=y;
		this.color=color;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<50;i++) {
			try {
				Thread.sleep(40);
			}catch (InterruptedException ex) {
				ex.printStackTrace();
			}
			//g.setColor(color);
			g.drawOval(x+5*i, y+5*i, 40, 40);
		}	
	}
}

程序依旧可以正常运行,但是并没有圆圈颜色交替的效果,这是因为Second_Try类中使用的始终是同一个画笔,而画笔最后的颜色设置成了yellow,覆盖了另外两种颜色,所以只有黄色圆圈。

程序运行结果如下 :
在这里插入图片描述

拓展

稍微改动以下重写的run()方法就可以绘制不同的好看有趣的图形了
米字
在这里插入图片描述
浪漫烟花
这个就留给读者自己思考吧~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java实现线程返回值的方法有多种。其中一种方法是通过继承Thread类或者实现Runnable接口,在子线程中设置共享变量来获取返回值。这种方法的缺点是不能精确判断子线程是否执行完成。另一种方法是通过实现Callable接口,使用FutureTask启动子线程,然后使用FutureTask的get()方法获取返回值。这种方法可以精确地获取返回值。 以下是两种方法的示例代码: 方法一,通过设置共享变量获取返回值: ```java public class TestThread extends Thread { public String value = null; @Override public void run() { System.out.println("TestThread start...."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("TestThread end"); value = "TestThread"; } } public class Main { public static void main(String[] args) throws InterruptedException { TestThread thread = new TestThread(); thread.start(); while (thread.value == null) { Thread.sleep(100); } System.out.println(thread.value); } } ``` 方法二,使用Callable和FutureTask获取返回值: ```java import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class TestCallable implements Callable<String> { @Override public String call() throws Exception { System.out.println("TestCallable start...."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("TestCallable end"); return "TestCallable"; } } public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<>(new TestCallable()); Thread thread = new Thread(futureTask); thread.start(); String value = futureTask.get(); System.out.println(value); } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值