前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java并发编程(1):Java多线程-基本线程类-基础知识复习笔记

java并发编程(1):Java多线程-基本线程类-基础知识复习笔记

原创
作者头像
周陆军博客
发布2023-04-09 22:48:55
2340
发布2023-04-09 22:48:55
举报
文章被收录于专栏:前端博客前端博客

复习资料:《同步与异步:并发/并行/进程/线程/多cpu/多核/超线程/管程 》

基本线程类

基本线程类

基本线程类指的是Thread类,Runnable接口,Callable接口

继承Thread创建线程

继承java.lang.Thread类创建线程是最简单的一种方法,也最直接。

public class MyThread1 extends Thread {}

种创建方式,把线程执行的逻辑代码直接写在了Thread的子类中,这样根据线程的概念模型,虚拟CPU和代码混合在一起了。并且java是单继承机制,线程体继承Thread类后,就不能继承其他类了,线程的扩展受影响

实现Runnable接口创建线程

为了构建结构清晰线程程序,可以把代码独立出来形成线程目标对象,然后传给Thread对象。通常,实现Runnable接口的类创建的对象,称作线程的目标对象。

public class MyThreadTarget implements Runnable{ }

出线程目标对象和Thread分开了,并传递给了Thread。如果有比较复杂的数据要处理,可以在线程目标对象中引入数据。使用这种方式获得线程的名字就稍微复杂一些,需要使用到Thread中的静态方法,获得当前线程对象,然后再调用getName()方法。这种方式在较复杂的程序中用得比较普遍。

Callable

future模式:并发模式的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态

代码语言:javascript
复制
ExecutorService e = Executors.newFixedThreadPool(3);
 //submit方法有多重参数版本,及支持callable也能够支持runnable接口类型.
Future future = e.submit(new myCallable());
future.isDone() //return true,false 无阻塞
future.get() // return 返回值,阻塞直到该线程运行结束

以上是基本方法,总结一下

多线程的基本操作

创建线程的方式 

  1. 将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法
  2. 声明实现 Runnable 接口的类。该类然后实现 run 方法

推荐方式二,因为接口方式比继承方式更灵活,也减少程序间的耦合。

线程API一览

  • start() 使线程处于就绪状态,Java虚拟机会调用该线程的run方法;
  • stop() 停止线程,已过时,存在不安全性:
    • 一是可能请理性的工作得不得完成;
    • 二是可能对锁定的对象进行“解锁”,导致数据不同步不一致的情况。

推荐 使用 interrupt() +抛异常 中断线程。

  • suspend() 暂停线程,已过时。
  • resume() 恢复线程,已过时。 suspend 与resume 不建议使用,存在缺陷:
    • 一是可能独占同步对象;
    • 二是导致数据不一致。
  • yield() 放弃当前线程的CPU资源。放弃时间不确认,也有可能刚刚放弃又获得CPU资源。
  • t.join() 等待该线程t 销毁终止。

获取当前线程信息

Thread.currentThread()

线程的分类

线程分为守护线程、用户线程。线程初始化默认为用户线程。

setDaemon(true) 将该线程标记为守护线程或用户线程

特性:设置守护线程,会作为进程的守护者,如果进程内没有其他非守护线程,那么守护线程也会被销毁,即使可能线程内没有运行结束

某线程a 中启动另外一个线程t,那么我们称线程t是线程a的一个子线程,而 线程a是线程t的父线程。

最典型的就是我们在main方法中 启动一个线程去执行。其中main方法隐含的main线程为父线程。

线程安全

线程安全就是每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的

线程安全就是说多线程访问同一代码,不会产生不确定的结果。

为什么有线程安全问题
为什么有线程安全问题

反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:

线程安全问题多是由全局变量和静态变量引起的

  • 当多个线程对共享数据只执行读操作,不执行写操作时,一般是线程安全的;
  • 当多个线程都执行写操作时,需要考虑线程同步来解决线程安全问题

线程同步

同步是保证多个线程之间共享同一个全局变量数据安全问题,保证数据原子性

多个线程操作一个资源的情况下,导致资源数据前后不一致。这样就需要协调线程的调度,即线程同步。 解决多个线程使用共通资源的方法是:线程操作资源时独占资源,其他线程不能访问资源。使用锁可以保证在某一代码段上只有一条线程访问共用资源。

有两种方式实现线程同步:

  • synchronized,使用同步代码块解决线程安全问题 
  • 同步锁(Lock)

Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。

线程状态

java多线程-线程状态转换
java多线程-线程状态转换

synchronized关键字用法

当它用来修饰一个方法或者一个代码块的时候(同步代码块:将可能会发生线程安全问题的代码给包裹起来),能够保证在同一时刻最多只有一个线程执行该段代码

  1. 原子性(互斥性):实现多线程的同步机制,使得锁内代码的运行必需先获得对应的锁,运行完后自动释放对应的锁。
  2. 内存可见性:在同一锁情况下,synchronized锁内代码保证变量的可见性。
  3. 可重入性:当一个线程获取一个对象的锁,再次请求该对象的锁时是可以再次获取该对象的锁的。

如果在synchronized锁内发生异常,锁会被释放。

  • synchronized方法 与 synchronized(this) 代码块 锁定的都是当前对象,不同的只是同步代码的范围
  • synchronized (非this对象x) 将对象x本身作为“对象监视器”:
    1. 多个线程同时执行 synchronized(x) 代码块,呈现同步效果。
    2. 当其他线程同时执行对象x里面的 synchronized方法时,呈现同步效果。
    3. 当其他线程同时执行对象x里面的 synchronized(this)方法时,呈现同步效果。
  • 静态synchronized方法 与 synchronized(calss)代码块 锁定的都是Class锁。Class 锁与 对象锁 不是同一个锁,两者同时使用情况可能呈异步效果。
  • 尽量不使用 synchronized(string),是因为string的实际锁为string的常量池对象,多个值相同的string对象可能持有同一个锁。

synchronized原理:

  • 首先有一个线程已经拿到了锁,其他线程已经有cup执行权,一直排队,等待释放锁。
  • 锁是在什么时候释放?代码执行完毕或者程序抛出异常都会被释放掉。
  • 锁已经被释放掉的话,其他线程开始进行抢锁(资源竞争),谁抢到谁进入同步中去,其他线程继续等待。

效率非常低,多个线程需要判断锁,比较消耗资源,抢锁的资源。——synchronized 只能有一个线程进行执行(就像厕所只有一个坑,好多人等着上厕所,谁进入厕所谁上锁,其他人在外等待),这个线程不释放锁的话,其他线程就一直等,就会产生死锁问题。

volatile关键字用法

多线程的内存模型:main memory(主存)、working memory(线程栈),在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)。

volatile与多线程
volatile与多线程

Volatile 关键字的作用是变量在多个线程之间可见,但不保证原子性。

  1. 内存可见性:保证变量的可见性,线程在每次使用变量的时候,都会读取变量修改后的最的值。
  2. 不保证原子性

针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后在某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能

线程间的通信方式

线程间通信的方式主要为共享内存、线程同步。

线程同步除了synchronized互斥同步外,也可以使用wait/notify实现等待、通知的机制。

  1. wait/notify属于Object类的方法,但wait和notify方法调用,必须获取对象的对象级别锁,即synchronized同步方法或同步块中使用。
  2. wait()方法:在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,或者其他某个线程中断当前线程,导致当前线程一直阻塞等待。等同wait方法。
    1. wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。 单位为毫秒。
    2. void wait(long timeout, int nanos) 与 wait(long timeout) 不同的是增加了额外的纳秒级别,更精细的等待时间控制。
  3. notfiy方法:唤醒在此对象监视器上等待的单个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
  4. notifyAll方法:唤醒在此对象监视器上等待的所有线程。

需要:wait被执行后,会自动释放锁,而notify被执行后,锁没有立刻释放,由synchronized同步块结束时释放。

应用场景:简单的生产、消费问题。

代码语言:javascript
复制
synchronized (lock) {//获取到对象锁lock
    try {
        lock.wait();//等待通信信号, 释放对象锁lock
    } catch (InterruptedException e) {
        e.printStackTrace();
    }	
}//接到通信信号
synchronized (lock) {
    //获取到对象锁lock
    lock.notify();//通知并唤醒某个正等待的线程
    //其他操作
}//释放对象锁lock

synchronized, wait, notify 是任何对象都具有的同步工具。

synchronized, wait, notify
synchronized, wait, notify

他们是应用于同步问题的人工线程调度工具。讲其本质,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。 wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。 当某代码并不持有监视器的使用权时(如上图的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。

参考文章:

Java多线程并发编程一览笔录 https://www.cnblogs.com/yw0219/p/10597041.html

Java 中的多线程你只要看这一篇就够了 https://juejin.im/entry/57339fe82e958a0066bf284f

阿里大牛详细讲解java多线程并发,PDT文档实战篇https://zhuanlan.zhihu.com/p/92958977

JAVA多线程之间实现同步+多线程并发同步解决方案 https://blog.csdn.net/yz2015/article/details/79436123

转载本站文章《java并发编程(1):Java多线程-基本线程类-基础知识复习笔记》, 请注明出处:https://www.zhoulujun.cn/html/java/KeyConcepts/8471.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本线程类
    • 基本线程类
      • 继承Thread创建线程
      • 实现Runnable接口创建线程
      • Callable
  • 多线程的基本操作
    • 创建线程的方式 
      • 线程API一览
        • 获取当前线程信息
          • 线程的分类
          • 线程安全
            • 线程同步
              • synchronized关键字用法
                • synchronized原理:
                  • volatile关键字用法
                  • 线程间的通信方式
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档