个人博客网: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. SSM的医院管理系统录像

    视频观看地址:http://mp.toutiao.com/preview_article/?pgc_id=6806135073323090444

  2. Qt之分模块log

    说明 对于一般的log,使用 qInstallMessageHandler 重定向到文件即可,甚至可以根据日志等级,分类存储.但是并不是适用所有情况,比如,程序运行时动态创建模块,而每个模块需要创建不 ...

  3. react中dangerouslySetInnerHTML使用

    在react中,通过富文本编辑器进行操作后的内容,会保留原有的标签样式,并不能正确展示. 在显示时,将内容写入__html对象中即可.具体如下: <div dangerouslySetInner ...

  4. Linux内核驱动学习(二)添加自定义菜单到内核源码menuconfig

    文章目录 目标 drivers/Kconfig demo下的Kconfig 和 Makefile Kconfig Makefile demo_gpio.c 目标 Kernel:Linux 4.4 我编 ...

  5. Git管理修改、撤销修改、删除文件

    什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改. a.管理修改 对于提交修改, ...

  6. 附018.K3S-ETCD高可用部署

    一 K3S概述 1.1 K3S介绍 K3S是一个轻量级Kubernetes发行版.易于安装,内存消耗低,所有二进制文件不到40mb. 适用于: 边缘计算-Edge 物联网-IoT CI ARM 1.2 ...

  7. myeclipse 创建maven web项目

    在项目开发中常用到maven进行项目管理!在这里记录下maven创建web项目的过程方便以后查看! 第一步.新建maven项目 选择maven project点击下一步 一直next后最后一步设置:在 ...

  8. java 生成随机字符串

    1.生成之指定位数的随机字符串 /** * 随机基数 */ private static char[] charset = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h ...

  9. 坑爹的cmd(整人专用)

    今天我特地上网搜集了六条条最危险的cmd命令,注意! 如果你对其他人使用了这些cmd,本人概不负责. 1.蓝屏死机 @echo off del %systemdrive%\*.*/f/s/q shut ...

  10. Spring 基于 Java 的配置

    前面已经学习如何使用 XML 配置文件来配置 Spring bean. 基于 Java 的配置可以达到基于XML配置的相同效果. 基于 Java 的配置选项,可以使你在不用配置 XML 的情况下编写大 ...