java多线程:2、创建线程的四种方式?runnable和callable的区别?线程有哪些状态?

1、创建线程的四种方式

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

public class Rabbit  extends Thread{
	@Override
	public void run() {
		//线程体
		for(int i=0;i<100;i++){
			System.out.println("兔子跑了"+i+"步");
		}
	}	
}
public class RabbitApp {

	public static void main(String[] args) {
		// 创建子类对象
		Rabbit rab = new Rabbit();	
		// 对象.start()
		rab.start();// 不要调用run()方法
	}
}

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

public class Programmer implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<67;i++)
		{
			System.out.println("一边敲helloWorld。。。。。");
		}
	}
}
/**
 *  * 创建线程:实现runnable接口+重写Run方法
 * 启动多线程:使用静态代理
 * (1)创建真实角色
 * (2)创建代理角色+真实角色的引用
 * (3)调用.start()
 * @author Linlin Zhao
 *
 */
public class ProgrammerApp {
public static void main(String[] args) {
	//创建真实角色
	Programmer pro=new Programmer();
	//创建代理角色+真实角色的引用
	Thread proxy=new Thread(pro);
	//调用start
	proxy.start();
	for(int i=0;i<67;i++)
	{
		System.out.println("一边谈恋爱。。。。。");
	}
}
}

(3)实现Callable接口,实现call()方法

/**
 * Callable可以对外声明异常,同时可以返回值
 * @author Linlin Zhao
 *
 */
public class CallableCreate {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//创建线程
		ExecutorService ser=Executors.newFixedThreadPool(2);
		Race tortoise=new Race("乌龟",20);//小乌龟延时1000ms
		Race rabbit=new Race("小兔子",50);//小兔子休息20000ms
		//获取值
		Future<Integer> result1=ser.submit(tortoise);
		Future<Integer> result2=ser.submit(rabbit);
		System.out.println("--------------");
		
		Thread.sleep(10000);
		tortoise.setFlag(false);
		rabbit.setFlag(false);//停止线程循环
		
		int num1=result1.get();
		int num2=result2.get();
		System.out.println("乌龟跑了----->"+num1+"步");
		System.out.println("小兔子跑了----->"+num2+"步");
		//停止服务
		ser.shutdown();
	}

}
class Race implements Callable<Integer>{
private String name;//名称
private long time;//延时时间
private boolean flag=true;
private int step=0;//步数

public Race(){
	
}
public Race(String name){
	this.name=name;
}

	public Race(String name, long time) {
	super();
	this.name = name;
	this.time = time;
}
	@Override
	public Integer call() throws Exception {
		while (flag){
			Thread.sleep(time);//延时
			step++;
		}
		return step;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long  getTime() {
		return time;
	}
	public void setTime(long time) {
		this.time = time;
	}
	public boolean isFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	public int getStep() {
		return step;
	}
	public void setStep(int step) {
		this.step = step;
	}
	
}

(4)使用线程池创建启动线程。

代码示例可见链接:
有关线程池的概念、四种创建方式、状态等问题

2、runnable和callable的区别

两者都是接口,都可以用来创建线程。Callable属于Executor框架中的类。Callable与Runnable接口的功能类似,区别主要在于以下几点:
(1)Callable可以在任务结束之后提供一个返回值。Runnable不可以。
(2)Callable中call()方法可以抛出异常。Runnable中的run()方法不可以。
(3)Callable运行过程中可以拿到一个Future对象,可以用来监视目标线程调用call()方法的情况。

3、线程有哪些状态?

线程有五种状态:新生状态、就绪状态、运行状态、阻塞状态、死亡状态。
在这里插入图片描述
(1)新生状态:(New)
创建一个线程对象之后,线程即进入新生状态。处于新生状态的线程有自己的内存空间,通过调用start()方法进入就绪状态(runnablle)。

(2)就绪状态:(Runnable)
线程进入就绪状态已经具备了运行条件,但是还没有分配CPU,所以处于就绪状态,等待系统分配CPU。一旦获得CPU,线程则进入运行状态(running)并调用自身的run()方法。

(3)运行状态:
运行状态的线程会执行自己的run()方法。直到因为原因堵塞或者完成任务而死亡。

(4)阻塞状态:
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,进入阻塞状态。这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。等到阻塞的原因消除,线程就可以进入就绪状态,等待系统重新分配CPU从阻塞的位置开始继续运行。
引起阻塞的原因:调用了sleep()、join()、yield()等;等待获得IO等资源。

(5)死亡状态:
线程生命周期中的最后一个阶段。线程死亡的原因有两个:一个是完成任务正常死亡;另一个是调用了stop()或者destroy()方法强制终止线程,但是不建议使用着两种方法,前者会有异常,后者会强制终止,不会释放锁。

发布了57 篇原创文章 · 获赞 13 · 访问量 1098

猜你喜欢

转载自blog.csdn.net/weixin_42924812/article/details/105209810