Juc01_多线程概述、四种实现方式、常用方法API、生命周期、买票案例、synchronized锁(一)

简介: ①. 多线程的概述(面试高频问点)②. 多线程的实现方式①. 继承Thread②. 实现Runnable接口

说明


(1). 关于synchronized关键字底层原理参考如下文章


(2). Juc18_Java内存模型、对象头Mark Word、实例数据、对齐填充、谈谈new Object( )占多大内存


(3). Juc19_从字节码角度看synchronize、Monitor类、monitorenter、monitorexit


(4). Juc20_Synchronized锁升级、无锁、偏向锁、轻量级锁、重量级锁、锁消除、锁粗化


①. 多线程的概述(面试高频问点)


  • ①. 为什么使用多线程及其重要


摩尔定律失效(硬件方面):


(1). 集成电路上可以容纳的晶体管数目在大约每经过18个月便会增加一倍,可是从2003年开始CPU主频已经不再翻倍,而是采用多核而不是更快的主频


(2). 在主频不再提高且核数不断增加的情况下,要想让程序更快就要用到并行或并发编程

高并发系统,异步+回调的生产需求(软件方面)


②. 进程、线程、管程(monitor 监视器)


线程就是程序执行的一条路径,一个进程中可以包含多条线程


多线程并发执行可以提高程序的效率,可以同时完成多项工作


举例:


[你打开一个word就是一个进程开启了,这个时候你重启后在打开word,这个时候有一个点击恢复的按钮,这就是一个线程,可能这个线程你看不到,你打字的时候,单词打错了,word中会有一个波浪线,这也是一个线程]


管程:Monitor(监视器),也就是我们平时所说的锁


(Monitor其实是一种同步机制,它的义务是保证(在同一时间)只有一个线程可以访问被保护的数据和代码)


JVM中同步时基于进入和退出的监视器对象(Monitor,管程),每个对象实例都有一个Monitor对象。


Monitor对象和JVM对象一起销毁,底层由C来实现


③. 多线程并行和并发的区别


并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行(需要多核CPU)


并发是指两个任务都请求运行,而处理器只能接收一个任务,就是把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行(12306抢票的案例)


④. wait | sleep的区别?功能都是当前线程暂停,有什么区别?


wait放开手去睡,放开手里的锁;wait是Object类中的方法


sleep握紧手去睡,醒了手里还有锁 ;sleep是Thread中的方法


⑤. synchronized 和 lock的区别?


(1). 原始构成
 a. synchronized是关键字属于JVM层面
 monitor对象,每个java对象都自带了一个monitor,需要拿到monitor对象才能做事情
 monitorenter(底层是通过monitor对象来完成,其实wait/notify等方法也依赖monitor对象,
 只能在同步块或方法中才能调用wait/notify等方法),进入
 monitorexit:退出
 b. lock是api层面的锁,主要使用ReentrantLock实现
(2). 使用方法
 a. synchronized不需要用户手动释放锁,当synchronized代码完成后系统会自动让线程释放
对锁的占用
 b. ReentrantLock则需要用户手动释放锁若没有主动释放锁,就有可能会导致死锁的现象
(3). 等待是否可中断?
 a. synchronized不可中断,除非抛出异常或者正常运行完成
 b. ReentrantLock可中断
 (设置超时时间tryLock(long timeout,TimeUnit unit),调用interrupt方法中断)
(4). 加锁是否公平
 a. synchronized非公平锁
 b. ReentrantLock两者都可以,默认是非公平锁,构造方法可以传入boolean值,true为公平锁,
 false为非公平锁
(5). 锁绑定多个Condition
 a.synchronized没有
 b.ReentrantLock用来实现分组唤醒需要唤醒线程们,可以精确唤醒,而不是像synchronized要么
 随机唤醒一个\要么多个


②. 多线程的实现方式


①. 继承Thread


  //注意:打印出来的结果会交替执行
  public class ThreadDemo{
      public static void main(String[] args) {
          //4.创建Thread类的子类对象
          MyThread myThread=new MyThread();
          //5.调用start()方法开启线程
          //[ 会自动调用run方法这是JVM做的事情,源码看不到 ]
          myThread.start();
          for (int i = 0; i < 100; i++) {
              System.out.println("我是主线程"+i);
          }
      }
  }
  class MyThread extends Thread{
      //2.重写run方法
      public void run(){
          //3.将要执行的代码写在run方法中
         for(int i=0;i<100;i++){
             System.out.println("我是线程"+i);
         }
      }
  }


②. 实现Runnable接口


  • ①. 源码分析如下:


微信图片_20220106173408.png


public class RunnableDemo {
    public static void main(String[] args) {
        //4.创建Runnable的子类对象
        MyRunnale mr=new MyRunnale(); 
        //5.将子类对象当做参数传递给Thread的构造函数,并开启线程
        //MyRunnale taget=mr; 多态
        new Thread(mr).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("我是主线程"+i);
        }
    }
}
//1.定义一个类实现Runnable
class MyRunnale implements Runnable{
    //2.重写run方法
    @Override
    public void run() {
        //3.将要执行的代码写在run方法中
        for (int i = 0; i < 1000; i++) {
            System.out.println("我是线程"+i);
        }
    }
}


②. 两种实现多线程方式的区别


  (1).查看源码
  a.继承Thread:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()
  方法
    b.实现Runnable:构造函数中传入了Runnable的引用,成员变量记住了它,start()调用
 run()方法时内部判断成员变量Runnable的引用是否为空,不为空编译时看的是Runnable的run(),
 运行时执行的是子类的run()方法
    (2).继承Thread
    a.好处是:可以直接使用Thread类中的方法,代码简单
    b.弊端是:如果已经有了父类,就不能用这种方法
    (3).实现Runnable接口
    a.好处是:即使自己定义的线程类有了父类也没有关系,因为有了父类可以实现接口,而且接口
可以多现实的
    b.弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,
代码复杂


相关文章
|
1天前
|
存储 监控 Java
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
77 12
|
17天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
17天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
42 3
|
1月前
|
JSON 安全 API
Python调用API接口的方法
Python调用API接口的方法
228 5
|
14天前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
14天前
|
Java 程序员 调度
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
|
2月前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
51 4
|
3月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
47 3
|
3月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
29 2
|
3月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
28 1
下一篇
开通oss服务