Java并发基础

Wesley13
• 阅读 620

一、多线程基础知识

1.进程和线程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。

线程:进程内部的一个独立执行单元;一个进程可以同时并发的运行多个线程,可以理解为一个进程便相当于一个单 CPU 操作系统,而线程便是这个系统中运行的多个任务。

进程和线程的区别:

  • 进程有独立的内存空间,进程中的数据存放空间(堆空间和栈空间)是独立的,至少有一个线程。线程堆空间是共享的,栈空间是独立的,线程消耗的资源比进程小的多。
  • 进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。
  • 程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行,线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。
  • 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点
  • 多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间

注意:

  • 因为一个进程中的多个线程是并发运行的,那么从微观角度看也是有先后顺序的,哪个线程执行完全取决于 CPU 的调度,程序员是干涉不了的。而这也就造成的多线程的随机性。
  • Java 程序的进程里面至少包含两个线程,主进程也就是 main()方法线程,另外一个是垃圾回收机制线程。每当使用 java 命令执行一个类时,实际上都会启动一个 JVM,每一个 JVM 实际上就是在操作系统中启动了一个线程,java 本身具备了垃圾的收集机制,所以在 Java 运行时至少会启动两个线程。
  • 创建一个线程的开销比创建一个进程的开销小的多,那么我们在开发多任务运行的时候,通常考虑创建多线程,而不是创建多进程。

2.并行和并发

并行:指两个或多个时间在同一时刻发生(同时发生)
并发:指两个或多个事件在一个时间段内发生。

注意:单核处理器的计算机肯定不能并行的处理多个任务,只能是多个任务交替的在单个 CPU 上运行。

3.线程状态

  • 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
  • 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的成为“运行”。
  • 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得cpu 时间片后变为运行中状态(running)。
  • 阻塞(BLOCKED):表线程阻塞于锁。
  • 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
  • 超时等待(TIME_WAITING):该状态不同于WAITING,它可以在指定的时间内自行返回。
  • 终止(TERMINATED):表示该线程已经执行完毕。

Java并发基础

4.守护线程和非守护线程

守护线程:和主线程一起结束的线程,叫守护线程,例如典型的守护线程---(GC)垃圾回收线程。
非守护线程:主线程的结束不影响线程的执行的线程,也叫用户线程。例如用户线程。

注意:

  • 用户可以将非守护线程设置为守护线程,利用Thread.setDaemon()即可。thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程
  • 在守护线程中产生的新线程也是守护线程
  • 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑。

5.多线程和单线程的选择

对于单核CPU,如果是CPU密集型任务,如解压文件,多线程的性能反而不如单线程性能,因为解压文件需要一直占用CPU资源,如果采用多线程,线程切换导致的开销反而会让性能下降。但是对于比如交互类型的任务,肯定是需要使用多线程的、而对于多核CPU,对于解压文件来说,多线程肯定优于单线程,因为多个线程能够更加充分利用每个核的资源。虽然多线程能够提升程序性能,但是相对于单线程来说,它的编程要复杂地多,要考虑线程安全问题。因此,在实际编程过程中,要根据实际情况具体选择。

6.上下文切换

对于单核CPU来说,同一个时刻,CPU只能运行一个线程,当运行一个线程过程中发生线程切换,去运行另外一个线程。这个过程即线程的上下文切换,进程的上下文切换类似。注意:对于线程的上下文切换实际上就是存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。多线程可以提高程序的运行效率,但是线程的创建和销毁,以及线程的上下文切换非常的消耗资源,所以有时候多线程未必能带给我们想要的效果。

7.同步与异步

同步:单任务模式,排队执行,在一个操作结束前,另外一个操作需要等待。
异步:多任务模式,多个任务切换占用CPU时间片,切换执行,多线程是异步的。线程被调用的时机是随机的。

二、多线程--java线程的创建

java中创建线程的话,一般有两种方式:1)继承Thread类;2)实现Runnable接口。

1.继承Thread类

 1 /**      
 2 *    继承Thread类,需要重写 Thread 类的 run()方法   
 3 */
 4 public class ThreadDemo extends Thread{
 5     
 6     @Override
 7     public void run() {
 8         System.out.println("子线程执行完毕");
 9     }
10     public static void main(String[] args) {
11         ThreadDemo t1 = new ThreadDemo(); 
12         t1.start();//启动线程,调用run
13         System.out.println("主线程执行完毕");
14     }
15 
16 }

结果输出:

主线程执行完毕
子线程执行完毕
或者
子线程执行完毕
主线程执行完毕

通过继承Thread类创建线程类后,通过start()方法启动线程,不是调用run()方法启动线程,run方法中只是定义需要执行的任务,如果调用run方法,即相当于在主线程中执行run方法,跟普通的方法调用没有任何区别,此时并不会创建一个新的线程来执行定义的任务。

2.实现Runnable接口

 1 public class RunableDemo implements Runnable{
 2 
 3     @Override
 4     public void run() {
 5         System.out.println("子线程执行完毕1");
 6     }
 7     
 8     public static void main(String[] args) {
 9         new Thread(new RunableDemo()).start();
10         System.out.println("主线程执行完毕1");
11     }
12 
13 }

结果输出:

子线程执行完毕1
主线程执行完毕1
或
主线程执行完毕1
子线程执行完毕1

通过实现Runnable接口,我们定义了一个子任务,然后将子任务交由Thread去执行。注意,这种方式必须将Runnable作为Thread类的参数,然后通过Thread的start方法来创建一个新线程来执行该子任务。如果调用Runnable的run方法的话,是不会创建新线程的,与普通的方法调用没有任何区别。

3.优先选择通过实现接口的方式来实现多线程的原因

  • 可以避免由于Java的单继承特性而带来的局限;
  • 增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的;
  • 适合多个相同程序代码的线程区处理同一资源的情况。
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
lucien-ma lucien-ma
3年前
什么是线程?什么是进程?
Java多线程基础进程和线程的概念应用程序是静态的概念,进程和线程是动态概念,有创建就有销毁,存在也是暂时的,不是永久性的。进程与线程的区别在于进程在运行时拥有独立的内存空间(每个进程所占有的内存都是独立的)多个线程是共享内存空间的,但是每个线程的执行时相互独立的,同时线程必须依赖于进程才能执行,单独的线程是无法执行的,由进程来控制多个线程的执行。
限时发布!非科班程序员金三银四求职经历
进程和线程的概念进程是具有独立功能的程序在一个数据集合上运行的过程。进程是系统进行资源分配的单位,实现的操作系统的并发。线程是比进程更小的能独立运行的单位,是  调度的基本单位,实现了进程内部的并发。线程成为了程序执行流的最小单位。进程状态转换图1.创建状态:进程正在被创建。2.就绪状态:进程已经分配到了除  之外的所有资源,只要分配到  就可以开
Wesley13 Wesley13
3年前
java多线程大汇总,线程与进程,线程调度,并发与并行,创建线程方式,线程生命周期,线程安全,线程通信,线程池
1.线程与进程进程是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间线程1、是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行.一个进程最少有一个线程2、线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程
Wesley13 Wesley13
3年前
4、jstack查看线程栈信息
1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6
Stella981 Stella981
3年前
Python进程、线程、协程的对比
1\.执行过程每个线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在进程中,由进程提供多个线程执行控制。每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。协程,又称微线程,Coroutine。执行过程中,在子程序内部可中断,然后转而
Wesley13 Wesley13
3年前
Java高级教程02
\TOC\1.Java线程1.1.多线程和多进程多进程:操作系统能够同时进行多个任务:每个app(word,播放器,浏览器)可以同时运行多线程:同一应用程序中哟多个顺序流同时执行线程是进程中的一部分1.2.线程的执行过程:!(
Wesley13 Wesley13
3年前
Java面试官都爱问的多线程和并发面试题汇总,多刷一题,多份安心!
Java多线程面试问题1、进程和线程之间有什么不同?一个进程是一个独立(selfcontained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序的单一进程。线程可以被称为轻量级进程。线程需要较少的资源来创建和驻留在进
Wesley13 Wesley13
3年前
Java多线程介绍
1\.线程概述1.1线程和进程进程是处于运行过程中的程序,并且具有一定的独立功能并发性:同一个时刻只能有一条指令执行,但多个进程指令被快速轮换执行并行:多条指令在多个处理器上同时执行线程是进程的执行单元1.2多