先复习一下线程的东西;

Java线程的内存模型

主内存与工作内存

Java内存模型主要定义了程序中各个变量的访问规则

  • 所有的变量都在主内存,Java堆(线程共享)

  • 每条线程都有自己的工作内存,虚拟机栈的部分区域(线程私有)

  • 线程的工作内存保存了该线程使用到的变量的主内存副本,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存的变量

内存间的交互操作

交互:即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存的实现细节。

内存交互的操作,是所有线程问题的根源

Java内存模型定义了八种方法来实现这个细节。

  • 必须保证下面的操作都是原子性的、不可再分的。

1:lock:把主内存变量标识为一条线程独占,此时不允许其他线程对此变量进行读写。

2:unlock:解锁一个主内存变量。

3:read:把一个主内存变量值读入到线程的工作内存,强调的是读入这个过程。

4:load:把read到变量值保存到线程工作内存中作为变量副本,强调的是读入的值的保存过程。

5:use:线程执行期间,把工作内存中的变量值传给字节码执行引擎。

6:assign(赋值):字节码执行引擎把运算结果传回工作内存,赋值给工作内存中的结果变量。

7:store:把工作内存中的变量值传送到主内存,强调传送的过程。

8:write:把store传送进来的变量值写入主内存的变量中,强调保存的过程。

线程状态

其中状态:

  • New:新建状态,线程中的任务代码还没有开始运行

  • Runnable:就绪状态(可执行状态)。新建线程调用start()方法,此时线程就处于就绪状态

    处于就绪状态的线程,并不一定立刻执行run方法,还需要同其他就绪线程竞争CPU,由Java的线程调度程序来调度执行线程。

  • Running:线程获得CPU使用权,开始执行run方法

    • 正在运行的线程,如果调用yield()方法,则强制进入Runnable就绪状态

  • Blocked:阻塞状态。几种进入阻塞的情况:

    • sleep方法:释放CPU,不释放锁。

    • join方法:A线程内调用B.join(),则串行执行,B线程先执行,A线程阻塞,底层是wait,并且释放锁。当B线程执行完毕,A线程继续执行。

    • 等待用户输入

    当sleep结束,join中断,或者用户输入(I/O完成),则线程进入Runnable就绪状态

  • Wating:等待队列。

    • 此线程调用了wait()方法,释放CPU,释放锁,进入等待队列。

    • 当其他线程调用notify()、notifyAll()方法,可以唤醒等待队列中的线程,进入锁池队列。

  • 锁池队列:如果此线程获取锁失败,则进入锁池队列,等待拿锁线程释放锁。

  • 线程挂起:一种主动行为,需要主动resume()进行恢复。不释放CPU

  • 死亡状态:线程run方法结束,或因异常退出run方法。线程生命周期结束。

强调:

这里的wait( ),被唤醒之后,是从阻塞的地方开始运行!!!,而不是重头开始运行!!

wait( )会放弃锁,唤醒之后,仍然需要争抢锁!

这就可能造成虚假唤醒,也就是说并发环境下,通过判断某个条件,让线程wait( ),是不能使用if的,必须使用while,这是官方文档在wait的使用方法里说明了的。

实现线程的方法

  1. 实现Callable接口

    执行call方法之后,可以获取一个Future对象,此对象调用get方法,即可获得返回的Object。

    此get方法阻塞,如果没有返回结果,就会阻塞;

  2. 实现Runnable接口(对任务的抽象)

  3. 继承Thread类(对线程的抽象)

// 继承Thread——对Thread类的抽象
public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("继承Thread");
    }
}
// 实现Runnable接口——对任务的抽象
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("实现Runnable接口");
    }
}
// 实现Callable接口——有返回值的任务
public class MyCallable implements Callable {
    @Override
    public String call() throws Exception {
        return "实现Callable接口";
    }

    public static void main(String[] args) {

        MyThread t1 = new MyThread();
        t1.start();

        MyRunnable myRunnable = new MyRunnable();
        Thread t2 = new Thread(myRunnable);
        t2.start();

        MyCallable t3 = new MyCallable();
        try {
        FutureTask<Integer> ft = new FutureTask<>(t3);        new Thread(ft).start();        String res = ft.get();        System.out.println(res);
     } catch (Exception e) { e.printStackTrace(); } } }

【JUC】1.线程的更多相关文章

  1. 细说JUC的线程池架构

    前言 线程的创建是需要JVM和OS(操作系统)相互配合的,一次的创建要花费许多的资源. 1.首先,JVM要为该线程分配堆栈和初始化大量内存块,栈内存至少是1MB. 2.其次便是要进行系统的调用,在OS ...

  2. JUC自定义线程池练习

    JUC自定义线程池练习 首先上面该线程池的大致流程 自定义阻塞队列 首先定义一个双向的队列和锁一定两个等待的condition 本类用lock来控制多线程下的流程执行 take和push方法就是死等, ...

  3. JUC——ThreadFactory线程工厂类(四)

    ThreadFactory线程工厂类 在默认情况下如果要想创建一个线程类对象,大部分情况的选择是:直接通过子类为父类进行实例化,利用Runnable子类为Runnable接口实例化. 或者直接调用La ...

  4. JUC之线程间的通信

    线程通信 视频1: 2021.12.18 JUC视频学习片段 对上次多线程编程步骤补充(中部): 创建资源类,在资源类中创建属性和操作方法 在资源类里面操作 判断 干活 通知 创建多个线程,调用资源类 ...

  5. JUC之线程间定制化通信

    线程通信之定制化 之前文章中写了下Condition的使用,这里我们详细说下其中的用法: 首先使用Condition需要实例化Lock private Lock lock = new Reentran ...

  6. 【转】JUC下面线程池介绍

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new T ...

  7. JUC 一 线程池

    线程 线程,是程序执行的最小单元.线程是进程中的其中一个实体,是被系统独立调度和分派的基本单位 它可与同属一个进程的其它线程共享进程所拥有的全部资源. 一个线程可以创建和撤消另一个线程,同一进程中的多 ...

  8. JUC之线程池-三大方法-七大参数-四种拒绝策略

    线程池:重点 三大方法 七大参数 四种拒绝策略 使用池化技术的理由: 我们的程序伴随着创建销毁线程十分浪费资源, 所以使用线程池,先创建线程,随用随取,用完归还 简单来说就是节约了资源. 使用线程池的 ...

  9. JUC之线程池基础

    线程池 定义和方法 线程池的工作时控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等待其他线程执行完成,再从队列中取出任 ...

  10. JUC之线程池基础与简单源码分析

    线程池 定义和方法 线程池的工作时控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等待其他线程执行完成,再从队列中取出任 ...

随机推荐

  1. Qt编写气体安全管理系统12-设备双击

    一.前言 在编写这个项目的过程中,有个得到客户夸赞的小功能就是,设备按钮双击,在离线的时候是双击重连设备,在线的时候是双击弹出具体详情界面,回控设备,参数设置等.在modbus设备通信过程中,设定了超 ...

  2. 构造方法(和python初始化变量类似)

    public class Demo1 { int  name2=1; public Demo1(int name) { name=name2; } public Demo1() { } public ...

  3. Java EE互联网轻量级框架整合开发— SSM框架(中文版带书签)、原书代码

    Java EE互联网轻量级框架整合开发 第1部分 入门和技术基础 第1章 认识SSM框架和Redis 2 1.1 Spring框架 2 1.2 MyBatis简介 6 1.3 Spring MVC简介 ...

  4. Spring Cloud Ribbon 客户端负载均衡 4.3

      在分布式架构中,服务器端负载均衡通常是由Nginx实现分发请求的,而客户端的同一个实例部署在多个应用上时,也需要实现负载均衡.那么Spring Cloud中是否提供了这种负载均衡的功能呢?答案是肯 ...

  5. 利用VisualSVN修改配置库名称

    相信大家都听说过SVN的大名,至于它的用途以及如何安装不在本文范围内,这里主要讲解如何利用VisualSVN来更改配置库的名称,前提是你的SVN服务必须用VisualSVN搭建,网上几乎没有这方面的文 ...

  6. DB2 索引(2)

    最近研究了一点DB2索引相关的东西,做一个总结: (1)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构: (2)在经常用连接的列(join)上建索引,这些列主要是一些外键,可以加快连接的速 ...

  7. XML字符串和JAVA对象之间的转化

     1.JAXB中相关的注解.类和接口说明 JAXB 中主要的一些注解 - shenyunsese 的专栏 - CSDN 博客 注:教程很全面很详细.但是仅供参考. 主要疑问区分和说明:  1.1 @X ...

  8. QPS、TPS和系统吞吐量

    QPS:Queries Per Second,每秒查询率.是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. TPS:Transactions Per ...

  9. Python进阶:metaclass谈

    metaclass 的超越变形特性有什么用? 来看yaml的实例: import yaml class Monster(yaml.YAMLObject): yaml_tag = u'!Monster' ...

  10. FPS 游戏实现GDI透视

    FPS游戏可以说一直都比较热门,典型的代表有反恐精英,穿越火线,绝地求生等,基本上只要是FPS游戏都会有透视挂的存在,而透视挂还分为很多种类型,常见的有D3D透视,方框透视,还有一些比较高端的显卡透视 ...