创建多线程的几种方法介绍

目录

线程的概念及单线程多线程区别

创建多线程——继承线程类

创建多线程——实现Runnable接口

创建多线程——匿名类

总结


线程的概念及单线程多线程区别

首先要理解进程(Processor)和线程(Thread)的区别
进程:我们玩游戏时,启动一个 lol.exe 就叫一个进程。 接着又启动一个 DOTA.exe ,这叫两个进程。
线程:线程是在进程内部同时做的事情,比如在 LOL 里,有很多事情要同时做,比如"盖伦” 击杀“提莫”,同时“赏金猎人”又在击杀“盲僧”,这就是由多线程来实现的。
总的可以这样说:进程是一个事件,线程是具体的动作,比如我们出去玩,玩就是一个进程,而具体 “玩什么”, “怎么玩” 就是线程。

单线程与多线程区别(类比于打游戏):
单线程时,盖伦打提莫,盲僧打亚索两个动作,只能分别进行;
多线程时,盖伦打提莫,盲僧打亚索两个动作,可以同时进行。

  • 我们可以设计一个类Hero,定义变量和攻击方法(attack)
package test;

public class Hero {
    // 定义变量 
	public String name;
	public float hp;
	public int damage;
	
    // 定义攻击方法
	public void attack(Hero h) {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		h.hp -= damage;
		System.out.format("%s 正在攻击  %s, %s 的血变成了 %.0f%n", name, h.name, h.name, h.hp);
		
		if(h.isDead()) {
			System.out.println(h.name + "死了!");
		}
	}
	public boolean isDead() {
		return hp <= 0 ? true : false;
	}
}

 

  • 设计一个类HeroAssignment,实例化Hero对象,并赋值。(注意可以利用构造法赋值)
package test;

public class HeroAssignment {
	public HeroAssignment() {
		
	}
	
	Hero gareen = new Hero("盖伦", 616, 50);
	Hero teemo = new Hero("提莫", 300, 30);
	Hero leesin = new Hero("盲僧", 455, 80);
	Hero yasuo = new Hero("亚索", 500, 65);
}
  • 在mian函数中,实例化赋值类,并运行 Hero 的 attack方法
    package test;
    
    public class mainRun {
    	public static void main(String[] args) {
    		
    		HeroAssignment ha = new HeroAssignment();
    		// 盖伦打提莫
    		while (!ha.teemo.isDead())
    			ha.gareen.attack(ha.teemo);
    		// 盲僧打亚索
    		while (!ha.yasuo.isDead()) {
    			ha.leesin.attack(ha.yasuo);
    		}
    	}
    }

     

  • 输出结果为:
盖伦 正在攻击  提莫, 提莫 的血变成了 250
盖伦 正在攻击  提莫, 提莫 的血变成了 200
盖伦 正在攻击  提莫, 提莫 的血变成了 150
盖伦 正在攻击  提莫, 提莫 的血变成了 100
盖伦 正在攻击  提莫, 提莫 的血变成了 50
盖伦 正在攻击  提莫, 提莫 的血变成了 0
提莫死了!
盲僧 正在攻击  亚索, 亚索 的血变成了 420
盲僧 正在攻击  亚索, 亚索 的血变成了 340
盲僧 正在攻击  亚索, 亚索 的血变成了 260
盲僧 正在攻击  亚索, 亚索 的血变成了 180
盲僧 正在攻击  亚索, 亚索 的血变成了 100
盲僧 正在攻击  亚索, 亚索 的血变成了 20
盲僧 正在攻击  亚索, 亚索 的血变成了 -60
亚索死了!
 

创建多线程——继承线程类

  • 设计一个类KillThread继承Thread,并且重写run方法
package test;

public class KillThread extends Thread {
	private Hero h1;
	private Hero h2;

	public KillThread(Hero h1, Hero h2) {
		this.h1 = h1;
		this.h2 = h2;
	}

	@Override
	public void run() {
		while (!h2.isDead()) {
			h1.attack(h2);
		}
	}
}
  • 启动线程办法: 实例化一个KillThread对象,并且调用其start方法
package test;

public class mainRun {
	public static void main(String[] args) {
		// 引入赋值对象
		HeroAssignment ha = new HeroAssignment();

        // 实例化对象,并调用start方法
		KillThread kt1 = new KillThread(ha.gareen, ha.teemo);
		kt1.start();
		KillThread kt2 = new KillThread(ha.leesin, ha.yasuo);
		kt2.start();
		
	}
}
  • 输出结果为:(可以看到盲僧攻击亚索的同时,盖伦也在攻击提莫)
盲僧 正在攻击  亚索, 亚索 的血变成了 420
盖伦 正在攻击  提莫, 提莫 的血变成了 250
盖伦 正在攻击  提莫, 提莫 的血变成了 200
盲僧 正在攻击  亚索, 亚索 的血变成了 340
盲僧 正在攻击  亚索, 亚索 的血变成了 260
盖伦 正在攻击  提莫, 提莫 的血变成了 150
盖伦 正在攻击  提莫, 提莫 的血变成了 100
盲僧 正在攻击  亚索, 亚索 的血变成了 180
盲僧 正在攻击  亚索, 亚索 的血变成了 100
盖伦 正在攻击  提莫, 提莫 的血变成了 50
盲僧 正在攻击  亚索, 亚索 的血变成了 20
盖伦 正在攻击  提莫, 提莫 的血变成了 0
提莫死了!
盲僧 正在攻击  亚索, 亚索 的血变成了 -60
亚索死了!

 

创建多线程——实现Runnable接口

  • 设计一个类KillRunnable实现Runnable接口,并且重写run方法
package test;

public class KillRunnable implements Runnable{
	private Hero h1;
	private Hero h2;

	public KillRunnable(Hero h1, Hero h2){
		this.h1 = h1;
		this.h2 = h2;
	}

	@Override
	public void run() {
		while (!h2.isDead()) {
			h1.attack(h2);
		}
	}
	
}

 

  • 启动线程办法: 实例化一个KillRunnable对象,并且调用其start方法
package test;

public class mainRun {
	public static void main(String[] args) {
		
		HeroAssignment ha = new HeroAssignment();
		KillRunnable kr1 = new KillRunnable(ha.gareen, ha.teemo);
		new Thread(kr1).start();
		KillRunnable kr2 = new KillRunnable(ha.leesin, ha.yasuo);
		new Thread(kr2).start();
		
	}
}
  • 输出结果为:(可以看到盲僧攻击亚索的同时,盖伦也在攻击提莫)
盖伦 正在攻击  提莫, 提莫 的血变成了 250
盲僧 正在攻击  亚索, 亚索 的血变成了 420
盲僧 正在攻击  亚索, 亚索 的血变成了 340
盖伦 正在攻击  提莫, 提莫 的血变成了 200
盲僧 正在攻击  亚索, 亚索 的血变成了 260
盖伦 正在攻击  提莫, 提莫 的血变成了 150
盖伦 正在攻击  提莫, 提莫 的血变成了 100
盲僧 正在攻击  亚索, 亚索 的血变成了 180
盲僧 正在攻击  亚索, 亚索 的血变成了 100
盖伦 正在攻击  提莫, 提莫 的血变成了 50
盖伦 正在攻击  提莫, 提莫 的血变成了 0
盲僧 正在攻击  亚索, 亚索 的血变成了 20
提莫死了!
盲僧 正在攻击  亚索, 亚索 的血变成了 -60
亚索死了!

创建多线程——匿名类

  • 继承Thread,重写run方法,直接在run方法中写业务代码
package test;

public class mainRun {
	public static void main(String[] args) {
		
		HeroAssignment ha = new HeroAssignment();
		// 匿名类
		Thread t1 = new Thread() {
			@Override
			public void run() {
				//匿名类中用到外部的局部变量teemo,必须把teemo声明为final
                //但是在JDK7以后,就不是必须加final的了
				while(!ha.teemo.isDead()) {
					ha.gareen.attack(ha.teemo);
				}
			}
		};
		t1.start();
		
		Thread t2 = new Thread() {
			@Override
			public void run() {
				while(!ha.yasuo.isDead()) {
					ha.leesin.attack(ha.yasuo);
				}
			}
		};
		t2.start();
		
	}
}

 

  • 输出结果为:(可以看到盲僧攻击亚索的同时,盖伦也在攻击提莫)
盖伦 正在攻击  提莫, 提莫 的血变成了 250
盲僧 正在攻击  亚索, 亚索 的血变成了 420
盖伦 正在攻击  提莫, 提莫 的血变成了 200
盲僧 正在攻击  亚索, 亚索 的血变成了 340
盲僧 正在攻击  亚索, 亚索 的血变成了 260
盖伦 正在攻击  提莫, 提莫 的血变成了 150
盖伦 正在攻击  提莫, 提莫 的血变成了 100
盲僧 正在攻击  亚索, 亚索 的血变成了 180
盲僧 正在攻击  亚索, 亚索 的血变成了 100
盖伦 正在攻击  提莫, 提莫 的血变成了 50
盖伦 正在攻击  提莫, 提莫 的血变成了 0
盲僧 正在攻击  亚索, 亚索 的血变成了 20
提莫死了!
盲僧 正在攻击  亚索, 亚索 的血变成了 -60
亚索死了!
 

总结

  1. 实现Runnable接口的线程类,还可以继承其他类。实现Runnable接口相对于扩展Thread类来说,具有无可比拟的优势。这种方式不仅有利于程序的健壮性,使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况。这样一来,线程、代码和数据资源三者有效分离,很好地体现了面向对象程序设计的思想。因此,几乎所有的多线程程序都是通过实现Runnable接口的方式来完成的。但是编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

  2. 继承Thread的线程类编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程,但不能再继承其他父类(Java单继承决定)。

  3. 启动线程是start()方法,run()并不能启动一个新的线程

start()和run()的区别

  • start()方法用来,开启线程,但是线程开启后并没有立即执行,他需要获取cpu的执行权才可以执行
  • run()方法是由jvm创建完本地操作系统级线程后回调的方法,不可以手动调用(否则就是普通方法)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值