Java23多线程4:总结和练习

1.多线程回顾

1.1 几个概念

  • 程序(Program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(Process)程序的一次执行过程,或是正在内存中运行的应用程序。程序是静态的,进程是动态的,进程作为操作系统调度和分配资源的最小单位(亦是系统运行程序的基本单位)
  • 线程(Thread)进程可进一步细化成线程,它是程序内部的一条执行路径。线程是CPU调度和执行的最小单位

(栈管理运行,堆管理存储)

分时调度:所有线程轮流使用CPU的使用权,并且平均分配每个线程占用 CPU的时间。
抢占式调度:让优先级高的线程以较大的概率优先使用 CPU。如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

1.2 如何创建线程(重点)如何创建线程(重点)

方式1:继承 Thread类;
方式2:实现 Runnable接口;
方式3:实现 Callable接口;(JDK5.0新增)
方式4:使用线程池(JDK5.0新增)

1.3 Thread类的常用方法、线程的生命周期

  1. 线程中的构造器
//分配一个新的线程对象
public Thread();
//分配一个指定名字的新线程对象
public Thread(String name);
//指定创建线程的目标对象,它实现了 Runnable接口中的 Run()方法
public Thread(Runnable target);
//分配一个带有指定目标的新线程对象,并指定名字
public Thread(Runnable target, String name);
  1. 线程中的常用方法
public void run();//此线程要执行的任务,需要在此处定义代码。
public void start();//开始执行此线程;Java虚拟机调用此线程的 run()方法
public String getName();//获取当前线程的名称
public void setName(String name);//设置当前线程的名称
public static native Thread currentThread();//返回当前正在执行的线程对象的引用。在Thread子类中就是 this,通常用于主线程和 Runnable实现类
public static void sleep(long millis);//是当前正在运行的线程暂停 millis毫秒(暂时停止执行)
public static native void yield();//yield只是让当前线程暂停一下,让系统的线程调度器从新调度一次,希望优先级
  1. 线程的优先级
public final int getPriority():获取线程的优先级
public final int setPriority(int newPriority):改变线程的优先级,范围在[1, 10]之间。

Thread内部类声明的三个常量
MIN_PRIORITY (1) :最低优先级
NORM_PRIORITY (5) :普通优先级,默认情况下 main线程具有普通优先级。
MAX_PRIORITY (10) :最高优先级

  1. 线程的生命周期
    jdk5.0之前:
    JDK1.5 之前:5种状态

jdk5.0及之后:

 public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,

        WAITING,
        TIMED_WAITING,
        TERMINATED;
}

线程的生命周期jdk5.0之后

1.4 如何解决线程安全问题(重、难)

  • 什么是线程安全问题? 多个线程操作共享数据,就有可能出现线程安全问题。
  • 如何解决线程安全为题?
    • 同步机制:①同步代码块;②同步方法
      • 在实现Runnable接口的方式中,同步监视器可以考虑使用:this ;

      • 在继承Thread类的方式中,同步监视器 慎用 this,可以考虑使用:当前类.class 。

      • 非静态的同步方法,默认同步监视器是 this(要考虑是否唯一?);

      • 静态的同步方法,默认同步监视器是当前类本身。

    • jdk5.0新增:Lock接口及其实现类。(保证多个线程共用同一个Lock的实例)

1.5 同步机制相关的问题

  • 懒汉式的线程安全的写法;
  • 同步机制带来的问题:死锁
    • 死锁产生的条件及规避方式

1.6 线程间的通信

在同步机制下考虑线程间的通信;
wait()、notify()、notifyAll() 都需要使用在同步代码块或同步方法中。
高频笔试:wait() 、sleep()

2. 面试题

2.1 线程概述

2.1.1 什么是线程?

是程序内部的一条执行路径。线程是CPU调度和执行的最小单位

2.1.2 线程、进程区别

进程:对应一个运行中的程序;
线程:是运行中进程的一条或多条执行路径

2.1.3 多线程使用场景?

  • 手机app应用的图片的下载
  • 迅雷的下载
  • Tomcat服务器上web应用,多个客户端发起请求,Tomcat针对多个请求开辟多个线程处理

2.2 如何实现多线程

2.2.1 如何在Java中实现多线程

类似问题
创建多线程用Runnable 还是Thread?
多线程有几种实现方式,都是什么?

四种

2.2.2 Thread类中的start()和run()有什么区别?

start():①开启线程;②调用 run()

2.2.3 Java中Runnable和Callable有什么不同?

  • 实现Callable接口实现Runnable接口相比有哪些优点?

    1. call()方法有返回值,更灵活;
    2. call()可以使用 throws的方式处理异常,更灵活;
    3. Callable使用了泛型参数,可以指明具体的 call()方法的返回值类型,更灵活。
  • 实现Callable接口方式创建线程有哪些缺点?
    4. 如果主线程需要获取子线程 call()方法的返回值,则此时主线程是阻塞状态。

2.2.4 什么是线程池,为什么使用?

  1. 提高了程序执行的效率。(线程已经提前准备好了);
  2. 提高了资源的复用率。(执行完的线程并未销毁,而是可以继续执行其他的任务)
  3. 可以设置相关的参数,对线程池中的线程的使用进行管理。

2.3 常用方法、生命周期

2.3.1 sleep()和 yield()区别?

sleep():一旦调用就进入“阻塞”(或 TIMED_WAITING状态)
yield():释放 CPU的执行权,处在RUNNABLE的状态

2.3.2 线程创建中的方法?和属性情况?

2.3.3 线程的生命周期?

2.3.4 现成的基本状态以及状态之间的关系?

类似问题:
线程有哪些状态?如何让线程进入阻塞状态;
线程有几个状态?就绪和阻塞有什么不同?
Java的线程都有哪几种状态

2.3.5 stop()和suspend()方法为何不推荐使用?

stop():一旦执行,会释放同步监视器线程就结束了,导致 run()有未执行结束的代码,形成线程安全问题。
suspend():与 resume()搭配使用,导致死锁。

2.3.6 Java线程优先级是怎么定义的?

三个常量 ,[1, 10]

2.4 线程安全与同步机制

2.4.1 如何理解线程安全?它是如何造成的?

类似问题:
线程安全说一下??
对线程安全的理解?
什么是线程安全?

多个线程操作共享数据,导致出现线程不安全

2.4.2 多线程公用一个数据变量需要什么?

线程安全问题

2.4.3 多线程保证线程安全一般有几种方式?

类似问题:

  1. 如何理解线程安全问题,说明怎么解决线程安全问题?
  2. 说出你所知道线程同步的方法?
  3. 有哪些方法实现线程安全?
  4. 同步有几种实现方法,都是什么?
  5. 你在实际编码过程中是如何避免线程安全问题?
  6. 如何让线程同步?
  7. 多线程有什么同步措施?
  8. 同步有几种实现方法,都是什么?
  • 同步机制:①同步代码块;②同步方法
  • Lock

2.4.4 用什么关键字修饰同步方法?

synchronized

2.4.5 synchronized加在静态方法和普通方法区别?

同步监视器不同。静态方法中:当前类本身;非静态方法中:this

2.4.6 Java中synchronized和ReentrantLock区别?

类似问题:

  1. 多线程安全机制中 synchronized和 Lock的区别?
  2. 怎么实现线程安全,各个实现方法有什么区别?
  3. synchronized和 Lock的区别?
  • synchronized不管是同步代码块还是同步方法,都需要在结束一对“{}”之后,释放对同步监视器的调用;
  • Lock是通过调用两个方法控制需要被同步的代码,更灵活。
  • Lock作为接口,提供了多种实现类,适合更多复杂的场景,效率更高。

2.4.7 当一个线程进入一个对象的一个 synchronized方法后,其他线程是否可进入此对象的其他方法?

需要看其他方法是否使用 synchronized修饰,同步监视器的this是否是同一个。只有使用了 synchronized,并且是同一个this的前提下,就不能访问了。

2.4.8 线程同步和阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?

同步一定阻塞;阻塞不一定同步。

2.5 死锁

2.5.1 什么是死锁?产生的原因及必要条件?

  1. 出现死锁的原因?
  • 互斥条件
  • 占用且等待
  • 不可抢夺(或不可抢占)
  • 循环等待
  1. 如何避免死锁?

死锁一旦出现,基本很难人为干预,只能尽量规避,可以打破任意一个条件。为保证同步需要,只能对后面 3个条件进行破坏。

  • 针对条件1:互斥条件基本上无法被破坏。因为线程需要通过互斥解决安全问题;
  • 针对条件2:可以考虑一次申请所有需要的资源,就不会出现等待的问题;
  • 针对条件3:占用部分资源的线程,进一步申请其他资源时,若申请不到,就主动释放掉已占用的资源
  • 针对条件4:可以将资源改为线性顺序。申请资源时,先申请序号较小的,这样就避免了循环等待的问题

2.5.2 如何避免死锁?

死锁一旦出现,基本很难人为干预,只能尽量规避,可以打破任意一个条件。为保证同步需要,只能对后面 3个条件进行破坏。

  • 针对条件1:互斥条件基本上无法被破坏。因为线程需要通过互斥解决安全问题;
  • 针对条件2:可以考虑一次申请所有需要的资源,就不会出现等待的问题;
  • 针对条件3:占用部分资源的线程,进一步申请其他资源时,若申请不到,就主动释放掉已占用的资源
  • 针对条件4:可以将资源改为线性顺序。申请资源时,先申请序号较小的,这样就避免了循环等待的问题

2.6 线程通信

2.6.1 Java中notify()和 notifyAll()有什么区别?

  1. wait():线程一旦执行此方法,就进入等待状态。同时,释放同步监视器的调用
  2. notify():线程一旦执行此方法,就会唤醒 被wait()的线程中 优先级最高的线程的那一个线程(如果优先级相同,随机选择一个)。被唤醒的线程从当初 被wait()的位置继续执行。
  3. notifyAll():线程一旦执行此方法,就会唤醒 被wait()的所有线程。

2.6.2 为什么wait()和 notify()方法要在同步代码块中调用?

因为调用者必须是同步监视器

2.6.3 多线程:生产者、消费者代码(同步、wait、notify编程)

类似问题

  1. 如何用代码解决消费者和生产者问题?
  2. 多线程中生产者和消费者如何保证同步?
  3. 为代码实现消费者和 生产者
package com.mMultithreadOther;

/**
 * 生产者(Producer)&消费者(Consumer)
 */
public class Test6ProducerConsumer {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer pro1 = new Producer(clerk);
        Consumer con1 = new Consumer(clerk);
        Consumer con2 = new Consumer(clerk);
        pro1.setName("生产者1");
        con1.setName("消费者1");
        con2.setName("消费者2");
        pro1.start();
        con1.start();
        con2.start();
    }
}

/**
 * 店员
 */
class Clerk {
    //产品数量
    private int productNum = 0;

    //增加产品数量
    public synchronized void addProduct() {
        if (productNum >= 20) {
            try {
                wait();//等待消费者消费产品
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            productNum++;
            System.out.println(Thread.currentThread().getName() + "生产了第" + productNum + "个,产品。。。");

            //唤醒消费者
            notify();
        }
    }

    //减少产品数量
    public synchronized void minusProduct() {
        if (productNum <= 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "消费第" + productNum + "个,产品");
            productNum--;
        }

        //唤醒消费者
        notifyAll();
    }
}

/**
 * 生产者
 */
class Producer extends Thread {
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println("生产者开始生产。。。");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.addProduct();
        }
    }
}

/**
 * 消费者
 */
class Consumer extends Thread {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println("消费者开始消费");
            try {
                Thread.sleep(25);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.minusProduct();
        }
    }
}

2.6.4 wait()和 sleep()的区别?调用函数后状态有什么改变?

类似问题:

  1. 线程中sleep()和wait()有什么区别?
  2. Java线程阻塞调用 wait 函数和 sleep 的区别和联系
  3. wait()和 sleep()的区别,它们两个谁会释放锁?

1)相同点:

  • 一旦执行,当前线程都会进入阻塞;

2)不同点:

不同wait()sleep()
声明不同声明在Object类中声明在Thread类中,静态的
使用场景不同只能用在同步代码块 或同步方法 中可以在任何需要的场景中使用
同步代码块 或同步方法一旦执行,会释放同步监视器即便执行,也不会释放同步监视器
结束阻塞的方式到达指定时间,自动结束 或被notify()唤醒,结束阻塞到达指定时间自动结束阻塞

2.7单例模式(线程安全)

2.7.1 手写一个单例模式(Singleton),还要是安全的

饿汉式;
安全的懒汉式;
内部类;

2.7.2 手写一个懒汉式的单例模式&解决其线程问题,并说明思路?

类似问题:
手写一个懒汉式的单例模式

饿汉式;
安全的懒汉式;
内部类;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值