java多线程(一)线程的3种创建方式

一、线程的概念

1.概念

1.1进程是一个应用程序的运行,运用一个应用程序只有一个进程,一个进程拥有多个线程,在java中,main方法就是一个线程,而有时我们为了提高代码的执行效率,便需要创建多个线程,去分别执行不同的代码,

1.2举个简单的例子,一个main方法需要执行10个方法,每个方法的运行时间为10秒,所以执行完毕后所需要的总时间为10*10=100秒,那么线程我们创建10个线程,每一个线程去执行一个方法,所需的总时间也就10秒,效率提高了10倍,当然在实际开发中,创建线程也是需要花费时间和资源的。

二、创建线程

1.项目结构

1.1本次项目一共5个类,不多说。直接上UML图

在这里插入图片描述

2.需要执行的类People

2.1本类采用了单例模式中的懒汉模式,在jvm运行创建类,并只有一个实例。这样创建,便会暴露一些多线程下的一些问题,后面看结果。

2.2代码

package com.test;

public class People {
	
	private static People people;
	private static int count;
	private People(){
		
	}
	
	public static People getPeople(){
		if(null == people){
			people=new People();
		}
		return people;
	}
	
	public String say(){
		while (count < 10) {
			System.out.println(Thread.currentThread().getName()+count+"大半夜饿了,想吃泡面");
			count++;
		}
		return "eat";
	}
}

3.继承Thread

3.1在Java中,无论线程是通过哪种方式创建的,其最终还是一个Thread类。

3.2 直接上代码,ThreadOne


package com.test;

public class ThreadOne extends Thread{
	
	public ThreadOne(String name) {
		super(name);
	}

	@Override
	public void run() {
		People.getPeople().say();
	}
}

4. 实现runnable

4.1实现runnable接口的好处就是,接口是可以多实现的,类的继承却只能有一个父类,所以这也是和前面那种创建方式的最大区别。

4.2代码

package com.test;

public class ThreadTwo implements Runnable{

	@Override
	public void run() {
		People.getPeople().say();
	}

}

5.实现Callable

5.1实现Callable接口,用此方法创建的线程可以接受返回值和抛出异常,这也是和前面两张创建方式的区别。

5.2代码

package com.test;

import java.util.concurrent.Callable;

public class ThreadThree implements Callable<String>{

	@Override
	public String call() throws Exception{
		return People.getPeople().say();
	}
}

6.main方法

6.1 test类,这里在创建线程时,都给线程复了一个值,线程的名称,这方便在运行结果中进行分析。

6.2代码

package com.test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test {
	
	public static void main(String[] args) {
		//继承于Thread
		Thread t1=new ThreadOne("one");
		//实现Runnable
		Thread t2=new Thread(new ThreadTwo(),"two");
		//实现Callable
		Callable<String>  cb=new ThreadThree();
		FutureTask<String> fTask=new FutureTask<String>(cb);
		Thread t3=new Thread(fTask,"Three");
		t1.start();
		t2.start();
		t3.start();
		try {
			System.out.println(fTask.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
}

三、总结

1.运行结果

	1.1结果
one0大半夜饿了,想吃泡面
Three0大半夜饿了,想吃泡面
Three2大半夜饿了,想吃泡面
two0大半夜饿了,想吃泡面
Three3大半夜饿了,想吃泡面
Three5大半夜饿了,想吃泡面
Three6大半夜饿了,想吃泡面
Three7大半夜饿了,想吃泡面
Three8大半夜饿了,想吃泡面
Three9大半夜饿了,想吃泡面
one1大半夜饿了,想吃泡面
two4大半夜饿了,想吃泡面
eat

2.结果分析

2.1首先在结果中最后一个值为eat,说明通过Callable接口的线程类可以返回值,至于异常,我在main中将它捕获了,便先不做考虑。

2.2按照常例,如果在main中直接调用peopel类里面的eat方法,运行结果应该是0-9各执行一次,但是在多线程的情况下,会发现,0被执行了3次。这下结果是这样,下次运行这个程序,可能是1被执行了3次。结果不固定,这显然不是我们所想要的。

2.3效率我们通过创建多个线程提高了,而结果我们又应该怎样去得到保障了。这就是我们后面的文章中会讲到,锁机制。一环扣一环,一口不能吃个大胖子,我们一步一步的去解决问题。

3.结语

我们千万不要把线程想得太复杂了,以前老是听人家说什么多线程,nio,很牛的样子,感觉很复杂,其实复杂的东西就是很多简单的东西组合而来,一步一步来,很容易理解,如果文章中有什么地方不对,或者觉得不够理解,还望指出,一定改之。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值