Java进阶 ——— Java多线程(一)之进程和线程

510 阅读5分钟

引言

讲到线程,不可避免的提到进程。而因为线程无法脱离进程单独存在,那什么是进程?
延伸阅读,Java多线程系列文章

Java进阶 ——— Java多线程(一)之进程和线程
Java进阶 ——— Java多线程(二)之如何开启多线程
Java进阶 ——— Java多线程(三)之多线程同步问题

什么是进程?

进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的最小单位。
例如手机运行的众多APP,每个可以理解为一个进程(实际上很多APP运行多个进程),每个APP直接互相独立,互不干扰。

什么是线程?

线程:进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。也就是程序执行的最小单位。
例如优酷APP,我们看视频的同时还可以缓存视频。看视频和缓存视频就是运行在进程中的两个线程。

进程和线程的关系

进程是一个独立的空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

  • 简而言之,一个程序至少有一个进程,一个进程至少有一个线程
  • 线程的划分尺度小于进程,使得多线程程序的并发性高。
  • 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
  • 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

举个不太准确的例子
北京火车站负责北京到上海的铁路运输管理。北京火车站就是一个进程。这个进程负责整个线路的调度和分配。而北京到上海的线路,就是线程。这个线程是真正负责运送旅客和货物。

为什么要多线程?

现在要从北京运送大量旅客到上海,要在一天全部运送。如果只有一个线路,一辆火车去运送,那肯定是搞不定的,旅客在北京等的都疯了。

串行

那么是不是我可以加开多辆火车?然后依次送到上海?理论上是可以的。这种在一条线路上,所有火车依次行驶,就是串行,火车1、火车2、火车3依次行驶。只有火车1开动,火车2才能行驶。

那如果这个时候火车1出现故障,无法前进,该怎么办呢?或者铁路上只能同时开10辆火车,但是依然承载不了这么多旅客,一天时间还是运送不完?

并行

既然一条线路运送不了,那我开五条线路,每个线路都可以承载10辆火车,五个线路同时运行。不就可以满足了吗?

像上面这样,在一个进程中开启多个线程执行某个任务,就是多线程模式,多个线程同时运行,称为并行

如何开启多线程?

既然要开启多线程,该如何开启多线程呢?
在本篇文章,介绍了如何开启多线程Java进阶 ——— Java多线程(二)之如何开启多线程

多线程的安全问题

像上面这样,开启多个线程,同时运行,理论上是非常完美的解决办法。但是这个时候就会出现多线程的安全问题。

但是这时候每个线程接到通知:在天津站有也有不定量的旅客要乘车去上海。
1.第一条线路的第一辆火车到达天津,如果旅客全部上车了,后面的火车或者其他线路的火车不知道,到了天津站也停了,发现旅客全部上车走了…
2.如果需要三辆火车才能接走全部天津站的旅客,那到底哪几条线路的哪几趟火车到天津站停车呢?
3.如果三辆车同时接近天津站,但是天津站站台每次只能停一辆火车,那谁先进站呢?

当然,这是假想的问题,实际开发工作中,多线程的问题远不止这些,下面用代码来演示多线程的安全问题。
开启100个线程同时修改成员变量age,并打印值

public class ThreadTest {

	private int age = 10;
	public  void threadTest(){

		for (int i = 0; i < 100; i++) {
			Thread thread =	new Thread(new ThreadRunnable());
			thread.start();
		}
	}


	class ThreadRunnable implements Runnable {

		@Override
		public void run() {
			age++;
			System.out.println(age);
		}
	}
}

理想状态下,应该是线程依次增加age的值,从11增加到109。
来看下打印的结果

很明显,这个方法中线程并不是安全的,出现这种的原因有很多,最常见的原因就是,当某个线程1刚修改age的值,正要打印age的值,这时另一个线程2、3进入,又修改了age的值,并且打印结束,这时线程1才打印出age的值。

什么是线程安全呢?

简单理解:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的

或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。线程安全问题都是由全局变量及静态变量引起的

所以为了保证线程安全呢,就需要进行线程同步

什么是线程同步?

就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问

如何实现线程同步?

那么如何实现线程同步问题呢?下一篇文章我们继续了解如何实现线程同步?Java提供了哪些方式实现线程同步?

结束

本篇文章主要通过例子讲解什么是进程和线程,什么是多线程,什么是线程安全,什么是线程同步问题

感谢

www.cnblogs.com/lgk8023/p/6…
mp.weixin.qq.com/s?__biz=MzI…

www.cnblogs.com/duende99/p/…