多线程基础

写博客是自己对知识梳理,目前是写给自己看,算是自己学习后的作业,也是为了养成一个良好的习惯。

@[TOC](文章目录)

前言

本篇是笔者对多线程基础的总结。


一、线程简介

1. 什么是线程?
	线程是进程的基本执行单元,一个进程的所有任务都在线程中执行。
	
2. 进程和线程区别?
	进程是指在系统中正在运行的一个应用程序。
	区别:
		线程是处理器调度的基本单位,但是进程不是;
		地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间;
		资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的;
		执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
			
3. 为什么要用多线程?
	能适当提高程序的执行效率;
	能适当提高资源的利用率(CPU,内存);
	更快的响应时间。

二、线程创建

线程创建的3种方式:
1. 继承 Thead类 
	由于是继承的不够灵活不推荐使用 (也不推荐在项目中使用,也不会做过多介绍);
2. 实现 runable接口 
	重写该接口的run()方法 ,执行时调用start()方法,没有返回值。
	简化demo代码如下:
	public class RunnableThreadTest implements Runnable  {  
		@Override
	    public void run()  {  
	        for(int i = 0;i <100;i++)  {  
	            System.out.println(Thread.currentThread().getName()+" "+i);  
	        }  
	    }
	    public static void main(String[] args)  {
	    	RunnableThreadTest runnableThread = new RunnableThreadTest();
	    	Thread thread = new Thread(runnableThread);
	    	thread.start(); 
	    }     
	}
	
	这种在实际项目中用的也少,老鸟几乎不会用这种方式了。
	
3. 通过CallableFuture创建线程  
	重写Callablecall()方法,通过线程调用submit来执行线程,可以用FutureTask.get()来获取到返回值和捕捉异常。
	简化demo代码如下:
	    //创建线程池
        ExecutorService executors = Executors.newFixedThreadPool(2);
                //土地获取在查询时间段结束时间之前
        Future<String> takeFuture = executors.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
				//处理业务 。。。
                return "ok";
            }
        });
        try {
        	//获取到线程执行后的返回结果,其中 get() 是同步则塞方法
            String result = takeFuture.get();
        }catch (Exception e){
        	//捕捉多线程异常 并做业务处理
            log.error("多线程异常",e);
        }finally {
        	//释放资源 关闭线程池
            executors.shutdown();
        }
     目前在实际项目中,这种方式是主流。
根据以上的学习,来总结一下RunnableCallable的区别:
1. Callable规定(重写)的方法是call()Runnable规定(重写)的方法是run()2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的;
3. call方法可以抛出异常,run方法不可以。

以上也是为什么在实际项目用的都是CallableFuture创建线程的原因。

三、线程优先级

	线程是可以划分优先级,线程的优先级可以划分为1-10级别,其中 10是最高优先级 ,1 是最低优先级,默认都是 5 级别,
可以通过 Thread.setPriority(6) 来设置优控制先级。
	问题:是否优先级高的线程一定会优先执行?
	不一定,线程执行是由CPU决定,设置线程的优先级高只是让资源的尽量的倾斜,提高它优先执行的概率。

四、线程生命周期

		线程在运行的生命周期中可能出现的6种不同的状态,在给定的一个时刻,线程只能处于其中的一个状态,
	具体请看下图:

来自并发编程的艺术

线程的生命周期:
	1. 线程创建后,调用start()方法开始运行中状态;
	2.1. 运行中状态如果调用了wait()join()方法会进入到等待状态;
	2.2. 运行中状态如果调用了wait(long)join(long)sleep(long)等超时限制的方法会进入到超时等待状态;
	2.3. 当线程调用了同步方法时,在没有获取锁的情况下就会到阻塞状态,获取到锁后会到运行中状态;
	2.4. 运行中状态如果执行了run()方法之后就会进入到终止状态;
	3. 当等待状态或超时等待状态调用 notify()notifyAll()状态后会重新进入到运行中状态。

具体如下图所示:

在这里插入图片描述
该图来自《并发编程的艺术》。

五、线程开销

1. 开启线程需要占用一定的内存空间,(默认情况下,主线程1M,子线程512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能;
2. 线程越多,cpu在调度线程上的开销就越大;
3. 程序设计更加复杂:比如线程之间的通讯、多线程的数据共享。

总结

1. 大量的线程的开销非常大,推荐用线程池管理线程;
2. 线程创建推荐使用 通过CallableFuture创建线程;
3. 根据实际的业务评估是否要使用多线程,杜绝不必要的使用多线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值