个人博客网:https://wushaopei.github.io/    (你想要这里多有)

1、程序、进程、线程的理解

1.1 概念

  • 程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(process)是程序的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生、存在和消亡的过程。

如:运行中的QQ,运行中的MP3播放器
           程序是静态的,进程是动态的

  • 线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。

若一个程序可同一时间执行多个线程,就是支持多线程的

1.2 进程与多线程

每个Java程序都有一个隐含的主线程: main 方法

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
  • 需要一些后台运行的程序时。

2、多线程的创建和启动

2.1 Thread 线程概念:

2.2 源码流程解析:

(1)Thread 类 与 Runnable接口

并且在Thread中有一个构造器的参数是Runnable的实现子类,所以当一个自定义类实现了Runnable接口后,可以通过newThread()作为构造参数传入来实现Thread多线程的创建。

如图:

(2)Thread 与 Runnable 、Callable 及Future Task 的关系

首先分析:

Future Task的底层实现了RunnableFuture 接口:

RunnableFuture 的底层实现了两个接口: Runnable , Future

而根据FutureTask 的构造方法和Callable 的类型可知:

由以上可以得知,通过自定义实现了Callable 接口的实例对象做为FutureTask 的构造器形参,然后因为实现了Runnable 接口的缘故,该对象可以做参数传入Thread对象的构造器中,用来创建新的多线程 thread ,并使用 start ()启动线程。

2.3 案例:mt子线程的创建和启动过程

3、线程中常用的API

interrupt() : 中断线程(也会将当前线程中的任务执行完毕会进行线程的一个标记,标记该线程是要被停止。
isInterrupted() :测试此线程是否已被中断。(如果线程的标记被标识成中断则返回true)

3、创建多线程的四中种方式

3.1 继承Thread

  1. 自定义一个类并继承Thread
  2. 重写run方法
  3. run方法中可以写入需要在分线程中执行的代码
  4. 创建Thread子类的对象
  5. 通过对象调用start方法

3.2 实现Runnable接口

  1. 自定义一个类并实现Runnable接口
  2. 重写run方法
  3. 在run方法中写入需要在分线程中执行的代码
  4. 创建Runnable实现类的对象
  5. 创建Thread对象并将Runnable实现类的对象作为实参传入到Thread的构造器中
  6. 通过Thread对象调用start方法

3.3 实现Callable接口

  1. 自定义一个类,并实现Callable接口
  2. 重写call方法,并返回结果
  3. 在call方法中实现需要在分线程中执行的代码
  4. 创建Callable接口的实现类的对象
  5. 创建FutureTask对象,并将Callable接口的实现类的对象作为实参传到FutureTask的构造器中
  6. 创建Thread对象,并将FutureTask对象作为实参传入到Thread构造器中
  7. 调用start方法

代码:

public class ThreadTest {

	public static void main(String[] args) throws Exception {
//4.创建Callable接口的实现类的对象
MyCallble myCallble = new MyCallble();
//5.创建FutureTask对象,并将Callable接口的实现类的对象作为实参传到FutureTask的构造器中
FutureTask<Integer> futureTask = new FutureTask<>(myCallble);
//6.创建Thread对象,并将FutureTask对象作为实参传入到Thread构造器中
Thread thread = new Thread(futureTask);
//7.调用start方法
thread.start(); //阻塞主线程,等待分线程返回数据结果,然后再向下执行。
Integer intNumber = futureTask.get(); System.out.println("===" + intNumber);
System.out.println("aaaaaaaaaaaaaaaaaaa");
}
}

//1.自定义一个类,并实现Callable接口
class MyCallble implements Callable<Integer>{ //2.重写call方法,并返回结果
@Override
public Integer call() throws Exception {
/*
* 3.需要在分线程中执行的代码
*/
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " == " + i);
}
return 100;
} }

3.4 线程池

                //创建一个线程池,根据需要创建新的线程,但在可用时将重用先前构建的线程。
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
//创建一个线程池,使用固定数量的线程操作了共享无界队列。
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
//创建一个执行器,使用一个单一的工作线程操作关闭一个无限的队列。
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
newCachedThreadPool.execute(new Runnable() { @Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "====" + i);
}
}
});
//关闭线程池
newCachedThreadPool.shutdown();

4、Thread的生命周期

要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:

  • 新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件
  • 运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run()方法定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或线程被提前强制性地中止

5、线程的同步机制

5.1 为什么要使用线程的同步机制?

多个线程在同时操作共享数据的时候可能会发生线程安全问题。

比如卖票:会发生重票,0票,负票的问题

5.2 解决线程安全问题的方式?
解决方法一 :同步代码块 :
格式 :

         synchronized (同步监视器) {
//操作共 享数据的代码
}

1.同步监视器 : 可以是任何对象
    注意 : 多个线程必须使用的是同一把锁(必须保证多个线程使用到的同步监视器是同一个对象)。
2.同步代码块内 : 操作共享数据的代码
(实现Runnable使用同步代码块案例 : 详见RunnableTest.java)
        
解决方法二:  同步方法
          格式 :

        public synchronized void say(){}  -- 修饰普通方法

默认的同步监视器是:this

           public static synchronized void say(){} -- 修饰静态方法

默认的同步监视是运行时类的对象。 例:Person.class

6、线程的单例模式

class Bank {
private Bank() {
}
private static Bank bank = null;
public static Bank getInstance() { if (bank == null) {
synchronized (Bank.class) {
if (bank == null) {
bank = new Bank();
}
}
} return bank;
}
}

7、死锁的问题

死锁的原因:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
代码:

                //创建两把锁
StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer(); new Thread() {
public void run() {
synchronized (s1) {
s2.append("A");
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (s2) {
s2.append("B");
System.out.print(s1);
System.out.print(s2);
}
}
}
}.start(); new Thread() {
public void run() {
synchronized (s2) {
s2.append("C");
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (s1) {
s1.append("D");
System.out.print(s2);
System.out.print(s1);
}
}
}
}.start();

8、线程通信

8.1 线程通信涉及到三个方法:

注意 :

  1. 上面个方法只能用在同步代码块和同步方法中
  2. 调用个方法实际上是调用监视对象中的方法

8.2 [面试题] wait和sleep的区别?

  1. sleep睡觉的时候会抱着锁。wait睡觉的时候会释放锁。
  2. sleep时间一到就自动唤醒,wait需要被其它线程调用notify/notifyAll才能唤醒。
  3. sleep是Thread中的方法, wait是Object中的方法。

8.3 [面试题] 继承Thread和实现Runnable的区别?

继承Thread :

          同步监视器 : 不可以使用this
          共享资源 : 需要使用static关键字修饰。
          单继承
          public static synchronized void say() - 默认锁是运行时类的对象。 比如 : Person.class

实现Runnable

        同步监视器 : 可以使用this
        共享资源 : 不需要使用static关键字修饰。
        多实现
        public synchronized void say(){} - 默认锁是this

9、同步的优点和缺点

  • 同步的优点 : 解决了线程安全问题
  • 同步的缺点 : 在同步代码块和同步方法的方法体执行时,只能有一个线程在执行。效率低。

10、ReentrantLock

代码:

class MyRunnable2 implements Runnable {
// 同一个类的多个对象共同拥有一份类变量
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() { while (true) {
lock.lock(); //锁住当前的线程
try {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " ==== " + ticket);
ticket--; } else {
return;
}
} finally {
//最后一定要手动解锁
lock.unlock();
}
}
}
}

注意 :ReentrantLock使用到的线程通信不是使用的wait()和notify()

JAVASE(十七) 多线程:程序、进程、线程与线程的生命周期、死锁、单例、同步锁的更多相关文章

  1. Java多线程——线程的优先级和生命周期

    Java多线程——线程的优先级和生命周期 摘要:本文主要介绍了线程的优先级以及线程有哪些生命周期. 部分内容来自以下博客: https://www.cnblogs.com/sunddenly/p/41 ...

  2. ☕【Java技术指南】「难点-核心-遗漏」Java线程状态流转及生命周期的技术指南(知识点串烧)!

    前提介绍 本章主要介绍相关线程声明周期的转换机制以及声明周期的流转关系以及相关AQS的实现和相关的基本原理,配合这相关官方文档的中英文互译的介绍. 线程状态流转及生命周期 当线程被创建并启动以后,它既 ...

  3. [转]Java 对象锁-synchronized()与线程的状态与生命周期

      线程的状态与生命周期 Java 对象锁-synchronized() ? 1 2 3 4 synchronized(someObject){   //对象锁 } 对象锁的使用说明: 1.对象锁的返 ...

  4. 【微信小程序开发•系列文章六】生命周期和路由

    这篇文章理论的知识比较多一些,都是个人观点,描述有失妥当的地方希望读者指出. [微信小程序开发•系列文章一]入门 [微信小程序开发•系列文章二]视图层 [微信小程序开发•系列文章三]数据层 [微信小程 ...

  5. 微信小程序把玩(五)页面生命周期

    原文:微信小程序把玩(五)页面生命周期 这里只要熟悉页面的基本生命周期即可,业务在指定生命周期函数内书写. 以下是官网给出的生命周期函数方法和状态图 上面的生周期函数图对于做Android 或者IOS ...

  6. 微信小程序把玩(四)应用生命周期

    原文:微信小程序把玩(四)应用生命周期 App() 函数用来注册一个小程序,注意必须在 app.js 中注册,且不能注册多个. 使用方式也跟Android中的Application中初始化一些全局信息 ...

  7. 多线程程序 怎样查看每个线程的cpu占用

    可以用下面的命令将 cpu 占用率高的线程找出来: ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu 这个命令首先指定参数'H',显示线程相关的 ...

  8. System、应用程序进程的Binder线程池和Handler消息循环

    首先看一张Android系统启动流程图:

  9. Java多线程2:线程的使用及其生命周期

    一.线程的使用方式 1.继承Thread类,重写父类的run()方法 优点:实现简单,只需实例化继承类的实例,即可使用线程 缺点:扩展性不足,Java是单继承的语言,如果一个类已经继承了其他类,就无法 ...

随机推荐

  1. zigbee通用IO口小作业

    独立新建工程并编写.编译代码,实现按键控制流水灯运行,完成以下任务要求: [1]程序开始运行时,D4.D3.D6.D5灯全亮一会,然后全灭一会,开始进入流水灯. [2]流水灯的运行过程为:D4灯亮,其 ...

  2. x86软路由虚拟化openwrt-koolshare-mod-v2.33联通双拨IPV6教程(第一篇)

    本文分两篇发布,此为第一篇,第二篇:https://www.cnblogs.com/zlAurora/p/12433302.html   年前TB购置了一台软路由,对家里网络来了个大改造,实现了PPP ...

  3. 线程和Python—Python多线程编程

    线程和Python 本节主要记录如何在 Python 中使用线程,其中包括全局解释器锁对线程的限制和对应的学习脚本. 全局解释器锁 Python 代码的执行是由 Python 虚拟机(又叫解释器主循环 ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目

    项目介绍 此个人博客项目底层基于 ABP Framework (不完全依赖)搭建项目 和免费开源跨平台的 .NET Core 3.1 开发,可作为 .NET Core 入门项目进行学习,支持各种主流数 ...

  5. PHPExcel生成Excel文件---提示导出文件或者文件扩展名不一致,或导出的文件或文件扩展名无效

    $data = Db::name('shop_cart')->where('phone','15555555555')->select(); $objPHPExcel = new PHPE ...

  6. 加密base64

    package com.lzkj.csp.bas.util; @SuppressWarnings("restriction") public class Base64Utils { ...

  7. 「雕爷学编程」Arduino动手做(35)——模拟量声音传感器

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  8. 「雕爷学编程」Arduino动手做(26)——4X4矩阵键盘模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  9. Spark Streaming 整合 Flume

    Spark Streaming 整合 Flume ​ 一.简介二.推送式方法        2.1 配置日志收集Flume        2.2 项目依赖        2.3 Spark Strea ...

  10. vue登录路由验证(转)

    转载自:https://blog.csdn.net/github_39088222/article/details/80749219 vue的项目的登录状态(如果用vuex状态管理,页面一刷新vuex ...