Java-多线程机制详解(一)

我们知道单线程的程序往往功能非常有限,就像一间工厂只雇佣一个工人,效率很低,而多线程机制就像雇佣了多名工人的工厂,生产效率十分的高。可见多线程机制在项目开发过程中的重要性。

文章结构(由于线程机制太大,会分开两篇来写):

1.进程与线程的理解;
2.多线程的优点;
3.线程的创建和启动三大方式;
4.线程的生命周期;


一、进程与线程的理解:

进程

定义:处于运行过程中的程序(程序进入内存);
特征
1.独立性–是系统中独立存在的实体,可拥有自己的资源、私有的地址空间。
2.动态性–程序只是一个讲台的指令集合,而进程是一个正在系统中运行的指令集合。
3.并发性–多个进程可在单个处理器上并发执行,且不会互相影响。

线程

定义:线程是进程的执行单元。
特征
1.线程可拥有自己的堆栈、自己的程序计算器和自己的局部遍历,但不拥有系统资源;
2.它与父进程的其他线程共享该进程所拥有的全部资源;
3.独立执行,而且不知道进程中是否还有其他线程存在;
4.执行的抢占式,即:当前运行的线程在任何时候都可能被挂起,以便另一线程可运行。

补充:并发与并行的区别:并行是指在同一时刻,有多态指令在多个处理器上同时执行。并发是指同一时刻只能有一条指令执行。


二、多线程优点:

(一)进程之间不能共享内存,但线程之间共享内存很容易;
(二)系统创建进程时需要为该进程重分配系统资源,但创建线程代价小很多。因此用多线程实现多任务并发比多进程的效率高。
(三)Java内置多线程功能支持,不是单纯地作为底层操作系统的调度方式。


三、线程的创建和启动三大方式:

(一)继承Thread类创建线程类;(二)实现Runnable接口创建线程类;(三)使用Callable和Future创建线程。
方式详情如下:

在这里插入图片描述

方式一代码:但是要注意–使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量
// 通过继承Thread类来创建线程类
public class TestThread extends Thread
{
	private int i ;
	// 重写run方法,run方法的方法体就是线程执行体
	public void run()
	{
			// 当线程类继承Thread类时,直接使用this即可获取当前线程
			// Thread对象的getName()返回当前该线程的名字
			// 因此可以直接调用getName()方法返回当前线程的名
			System.out.println(getName() +  " ");
	}
	public static void main(String[] args)
	{
		for (int i = 0; i < 100;  i++)
		{
			// 调用Thread的currentThread方法获取当前线程
			System.out.println(Thread.currentThread().getName()
				+  " " + i);
			if (i == 20)
			{
				// 创建、并启动一条线程.所有总共有两条线程。
				new TestThread().start();
			}
		}
	}
}
方式二代码:
// 通过实现Runnable接口来创建线程类
public class RunnableThread implements Runnable
{
	private int i ;
	// run方法同样是线程执行体
	public void run()
	{
			// 当线程类实现Runnable接口时,
			// 如果想获取当前线程,只能用Thread.currentThread()方法。
			System.out.println(Thread.currentThread().getName()
				+ "  " );
		
	}

	public static void main(String[] args)
	{
		for (int i = 0; i < 100;  i++)
		{
			System.out.println(Thread.currentThread().getName()
				+ "  " + i);
			if (i == 20)
			{
			//创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象。
				RunnableThread st = new RunnableThread();     
				// 通过new Thread(target , name)方法创建新线程
				new Thread(st , "新线程1").start();
				new Thread(st , "新线程2").start();
			}
		}
	}
}
方式三代码:与实现Runnable接口基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常。
public class CallableThread
{
	public static void main(String[] args)
	{
		// 创建Callable对象
		CallableThreadrt = new CallableThread();
		// 先使用Lambda表达式创建Callable<Integer>对象
		// 使用FutureTask来包装Callable对象
		FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
			int i = 0;
			
				System.out.println(Thread.currentThread().getName()
					+ " 的循环变量i的值:" );
			
			// call()方法可以有返回值
			return i;
		});
		for (int i = 0 ; i < 100 ; i++)
		{
			System.out.println(Thread.currentThread().getName()
				+ " 的循环变量i的值:" + i);
			if (i == 20)
			{
				// 实质还是以Callable对象来创建、并启动线程
				new Thread(task , "有返回值的线程").start();
			}
		}
		try
		{
			// 获取线程返回值
			System.out.println("子线程的返回值:" + task.get());
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}

补充:三种方式的比较:

实现Runnable和Callable接口的方式
优点
1.只是实现了接口,还可以继承其他类;
2.这种情况下,多个线程可共享同一个target对象,适合多个相同线程来处理同一份资源。从而可将CPU、代码和数据分开,形成清晰模型。
缺点:编程稍复杂,如需访问当前线程,必须用Thread.currentThread方法。

继承Thread类的方式

优点:编写简单,如需访问当前线程,只需使用this获得当前线程。
缺点:因为已经继承了Thread类,所以不能继承其他类了。


四、线程的生命周期:

五大状态:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、死亡(Dead)。

(一)新建(New)。

过程:仅仅由java虚拟机为其分配内存,并初始化成员变量的值,此时没有任何的线程动态特征。

(二)就绪(Runnable)。

过程:当线程对象调用start方法后,线程就处于就绪状态,Java虚拟机会为该线程创建方法调用栈和程序计数器。
注意
1.此状态的线程并没有开始运行,只是表示该线程可以运行。至于何时开始运行,取决于JVM里的线程调度器的调度,所以start后会有一个空档期不执行那个新开线程而还是执行原来线程。
2.如果直接调用run方法,系统会把线程对象当作普通对象,run也就变成一个普通方法,而不是线程执行体。直接调用run方法,那么在run方法返回之前其他线程无法并发执行。
3.只能对处于新建状态的线程调用start方法,否则引发IllegalThreadStatrException异常。
技巧:如果想子线程调用start后立刻执行,可以使用Thread.sleep(1)来使得当前线程睡眠1毫秒。

(三)运行(Running)。

过程:处理就绪状态的线程获得CPU,就可开始执行run执行体。

(四)阻塞(Blocked)。

在这里插入图片描述

(五)死亡(Dead)。

在这里插入图片描述


好了,Java-多线程机制详解(一)讲完了。欢迎在下面指出错误,共同学习!

转载请注明:【JackFrost的博客】
更多内容,可以访问JackFrost的博客
本博主最近会一直更新Java知识、数据结构与算法、设计模式的文章(因为最近在学习,哈哈哈),欢迎关注。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值