线程概念及创建线程

线程概念

线程是执行任务的路径,也是分配CPU时间的最小单位,也可以说线程是独立调度和分派的基本单位。

线程与进程区别

  • 程序运行起来就是进程,一个程序包含一个或多个进程,需要内存和CPU资源进行运算执行,每个进程有自己独立的内存空间,它是重量级的,需要的系统资源比较多。
  • 一个进程包含多个线程,多个线程共享一个进程的内存空间,每个线程单独执行一个任务,它是轻量级的,需要的系统资源比较少。

线程的实现

一、继承Thread类

  1. 继承Thread类
  2. 重写run方法
  3. 创建线程对象,调用start方法
public class MyThread extends Thread{

	/**
	 * 执行线程任务的方法
	 */
	public void run(){
		//Thread.currentThread()是获得系统当前执行的线程
		System.out.println(Thread.currentThread().getName()+"线程执行了!!!");
	}
	
	public static void main(String[] args) {
		//主线程中执行
		System.out.println(Thread.currentThread().getName()+"线程执行了!!!");
		//创建线程对象
		MyThread thread1 = new MyThread();
		MyThread thread2 = new MyThread();
		//启动线程
		thread1.start();
		thread2.start();
	}
}

这里有两个问题在面试时有可能会问到

启动线程使用start()和run()有什么区别?

启动线程要使用start()方法,只有start()方法会去创建并执行线程,运行任务,而run()方法里面写的只是我们要运行的任务,它不会启动线程。

线程执行为什么没有规律?

因为线程的执行是抢占式,它们去抢CPU,哪个线程抢到了CPU,哪个线程才执行。

二、实现Runnable接口

  1. 实现Runnable接口
  2. 实现run方法
  3. 创建自定义线程对象,作为参数传入Thread对象
  4. 调用start方法
public class MyRunnable implements Runnable{

	/**
	 * 实现run方法
	 */
	@Override
	public void run() {
		System.out.println("当前执行的线程是:"+Thread.currentThread().getName());
	}
	
	
	public static void main(String[] args) {
		//创建Thread对象,传入Runnable对象
		Thread thread1 = new Thread(new MyRunnable());
		//调用start方法
		thread1.start();
		//使用匿名内部类实现Runnable
		Thread thread2 = new Thread(new Runnable(){
			@Override
			public void run() {
				System.out.println("匿名内部类,当前执行的线程是:"+Thread.currentThread().getName());
			}
		});
		thread2.start();
		//使用Lambda实现Runnable
		Thread thread3 = new Thread(()->{
			System.out.println("Lambda,当前执行的线程是:"+Thread.currentThread().getName());
			});
		thread3.start();
	}

}
那么这两种方式有什么区别呢?
  • 实现Runnable接口还可以继续继承或者实现其他的接口或者类,但是一旦继承了Thread类,因为Java是单继承的,所以就不能继承其他的类了,会对后续的开发造成影响。
  • 实现Runnable接口就必须实现run()方法,而继承Thread类不用必须实现run()方法

三、实现Callable接口

实现Callable接口与上述两种方式的区别是,Callable接口可以返回值,但是上述两种方式实现的线程没有返回值

  1. 实现Callable接口,实现call方法
  2. 创建FutureTask对象,传入Callable对象
  3. 创建Thread对象,传入FutureTask对象
  4. 调用Thread对象的start方法
  5. 调用FutureTask对象的get方法,获得返回值
public class MyCallable implements Callable<Long>{

	@Override
	public Long call() throws Exception {
		System.out.println("执行call的线程是:"+Thread.currentThread().getName());
		//模拟执行耗时运算
		Long sum = 0L;
		for(int i = 0;i < 100000000L;i++){
			sum += i;
		}
		//返回结果
		return sum;
	}
	
	
	public static void main(String[] args) {
		//创建FutureTask对象,传入Callable对象
		FutureTask<Long> task = new FutureTask<>(new MyCallable());
		//创建Thread,传入FutureTask对象
		Thread thread = new Thread(task);
		//启动线程
		thread.start();
		//获得结果
		try {
//			long result = task.get();
			long result = task.get(5,TimeUnit.SECONDS);
			System.out.println("获得计算结果:"+result);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值