一、多线程基础知识

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):表示该线程已经执行完毕。

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类

 /**
* 继承Thread类,需要重写 Thread 类的 run()方法
*/
public class ThreadDemo extends Thread{ @Override
public void run() {
System.out.println("子线程执行完毕");
}
public static void main(String[] args) {
ThreadDemo t1 = new ThreadDemo();
t1.start();//启动线程,调用run
System.out.println("主线程执行完毕");
} }

结果输出:

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

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

2.实现Runnable接口

 public class RunableDemo implements Runnable{

     @Override
public void run() {
System.out.println("子线程执行完毕1");
} public static void main(String[] args) {
new Thread(new RunableDemo()).start();
System.out.println("主线程执行完毕1");
} }

结果输出:

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

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

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

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

  • 可以避免由于Java的单继承特性而带来的局限;
  • 增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的;
  • 适合多个相同程序代码的线程区处理同一资源的情况。

Java并发基础--多线程基础的更多相关文章

  1. java并发编程 线程基础

    java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...

  2. Java并发和多线程(一)基础知识

    1.java线程状态 Java中的线程可以处于下列状态之一: NEW: 至今尚未启动的线程处于这种状态. RUNNABLE: 正在 Java 虚拟机中执行的线程处于这种状态. BLOCKED: 受阻塞 ...

  3. java中的多线程 // 基础

    java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...

  4. Java并发与多线程教程(1)

    Java并发性与多线程介绍 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务 ...

  5. java并发与多线程面试题与问题集合

    http://www.importnew.com/12773.html     https://blog.csdn.net/u011163372/article/details/73995897    ...

  6. Java 并发和多线程(一) Java并发性和多线程介绍[转]

    作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...

  7. Java并发和多线程:序

      近期,和不少公司的"大牛"聊了聊,当中非常多是关于"并发和多线程"."系统架构"."分布式"等方面内容的.不少问题, ...

  8. Java并发和多线程2:3种方式实现数组求和

    本篇演示3个数组求和的例子. 例子1:单线程例子2:多线程,同步求和(如果没有计算完成,会阻塞)例子3:多线程,异步求和(先累加已经完成的计算结果) 例子1-代码 package cn.fansuni ...

  9. Java并发与多线程教程(2)

    Java同步块 Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) ...

随机推荐

  1. java中equals以及==的用法(简单介绍)

    简单介绍 equals方法是java.lang.Object类的方法 有两种用法说明: 一.对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比较方法不同. 1.“==”比较两 ...

  2. 第二章:RESTful API

    学习内容 使用Spring MVC编写Restful API 使用Spring MVC处理其他web应用常见的需求和场景 如何处理静态资源和异常,如何使用Spring MVC的拦截器,文件的上传下载, ...

  3. 【PTA 天梯赛训练】电话聊天狂人(简单map)

    输入格式: 输入首先给出正整数N(≤10^5),为通话记录条数.随后N行,每行给出一条通话记录.简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔. 输出格式: 在一行中给出 ...

  4. mysql 查询各个阶段所消耗的时间

  5. Python核心框架tornado的异步协程的2种方式

    什么是异步? 含义 :双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位 现象:没有共同的时钟,不考虑顺序来了 ...

  6. 使用deque保留有限的记录

    # 使用deque保留有限的记录 >>> from collections import deque >>> q = deque(maxlen=3) # 指定队列的 ...

  7. Linux : centOS 与 Ubuntu 安装 Nginx

    源码下载: wget http://nginx.org/download/nginx-1.14.0.tar.gz 解压:tar –zxvf xxx 安装依赖: yum -y install  open ...

  8. hive表格取差集

    hive 求两个集合的差集 业务场景是这样的,这里由两个hive表格A和B A的形式大概是这样的:uid B的形式大概是这样的:uid 我想要得到存在A中但是不存在B中的uid 具体代码如下 sele ...

  9. Python学习 :格式化输出

    方式一:使用占位符 % 常用占位符:% s   (s = string 字符串)     % d   (d = digit 整数(十进制))   %  f   ( f = float  浮点数) na ...

  10. 332. Reconstruct Itinerary

    class Solution { public: vector<string> path; unordered_map<string, multiset<string>& ...