高价值Java多线程面试题分析

问题一

A线程正在执行一个对象中的同步方法,B线程是否可以同时执行同一个对象中的非同步方法?

可以,两个线程运行所需资源不同,不需要抢占。

案例一、

package duoxiancheng2;

/**
 * @author yeqv
 * @program A2
 * @Classname Ms1
 * @Date 2022/2/7 19:08
 * @Email w16638771062@163.com
 */
public class Ms1 {
    //A线程正在执行一个对象中的同步方法,B线程是否可以同时执行同一个对象中的非同步方法?
    Object a = new Object();

    public static void main(String[] args) {
        var t = new Ms1();
        new Thread(() -> t.a1()).start();//A线程
        new Thread(() -> t.a2()).start();//B线程
    }

    void a1() {
        synchronized (a) {
            System.out.println("同步方法");
        }
    }

    void a2() {
        System.out.println("非同步方法");
    }
}

运行结果:

问题二

同上,B线程是否可以同时执行同一个对象中的另一个同步方法?

不可以,两个线程执行需要一个共同资源,共同资源加了同步锁,同一时刻只能一个线程占用。

案例二、

package duoxiancheng2;

import java.util.concurrent.TimeUnit;

/**
 * @author yeqv
 * @program A2
 * @Classname Ms2
 * @Date 2022/2/7 19:25
 * @Email w16638771062@163.com
 */
public class Ms2 {
    //同上,B线程是否可以同时执行同一个对象中的另一个同步方法?
    Object a = new Object();
    public static void main(String[] args) {
        var t = new Ms2();
        new Thread(() -> t.a1()).start();//A线程
        new Thread(() -> t.a2()).start();//B线程
    }
    void a1() {
        synchronized (a) {
            System.out.println("进入同步方法1");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("同步方法1结束");
        }
    }
    void a2() {
        synchronized (a) {
            System.out.println("进入同步方法2");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("同步方法2结束");

        }
    }
}

运行结果:

线程A先运行,占用资源。

等线程A运行完释放资源后,线程B才可以进入执行

线程B执行完

问题三

线程抛出异常会释放锁吗?

会,线程出现异常抛出后立刻释放资源。

案例三、

package duoxiancheng2;

import java.util.concurrent.TimeUnit;

/**
 * @author yeqv
 * @program A2
 * @Classname Ms3
 * @Date 2022/2/7 19:41
 * @Email w16638771062@163.com
 */
public class Ms3 {
    //线程抛出异常会释放锁吗?
    Object a = new Object();

    public static void main(String[] args) {
        var t = new Ms3();
        new Thread(() -> t.a1()).start();//A线程
        new Thread(() -> t.a2()).start();//B线程
    }

    void a1() {
        int c = 3;
        int b;
        synchronized (a) {
            System.out.println("进入同步方法1");
            try {
                b = c / 0;
                System.out.println(b);
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("同步方法1结束");
        }
    }

    void a2() {
        synchronized (a) {
            System.out.println("进入同步方法2");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("同步方法2结束");

        }
    }
}

结果: 方法一出现异常,立刻释放资源。线程二开始执行

问题四

写一个程序,证明AtomicInteger类比synchronized更高效

synchronized更高效

案例一

package duoxiancheng2;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author yeqv
 * @program A2
 * @Classname Ms4
 * @Date 2022/2/7 20:04
 * @Email w16638771062@163.com
 */
public class Ms4 {

    AtomicInteger n = new AtomicInteger(10000);
    int num = 10000;

    public static void main(String[] args) {

        var t = new Ms4();
        new Thread(t::minus, "T1").start();
        new Thread(t::minus, "T2").start();
        new Thread(t::minus, "T3").start();
        new Thread(t::minus, "T4").start();
        new Thread(t::minus, "T5").start();
        new Thread(t::minus, "T6").start();
        new Thread(t::minus, "T7").start();
        new Thread(t::minus, "T8").start();

    }

    void minus() {
        var a = System.currentTimeMillis();
        while (true) {
           /* if (n.get() > 0) {
                n.decrementAndGet();
                System.out.printf("%s 售出一张票,剩余%d张票。 %n", Thread.currentThread().getName(), n.get());
            } else {
                break;
            }*/
            synchronized (this) {
                if (num > 0) {
                    num--;
                    System.out.printf("%s 售出一张票,剩余%d张票。 %n", Thread.currentThread().getName(), num);
                } else {
                    break;
                }

            }

        }
        var b = System.currentTimeMillis();
        System.out.println(b - a);
    }
}

synchronized结果:

AtomicInteger结果:

问题五

写一个程序证明AtomXXX类的多个方法并不构成原子性

package demo16;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 写一个程序证明AtomXXX类的多个方法并不构成原子性
 */
public class T {
    AtomicInteger count = new AtomicInteger(0);

    void m() {
        for (int i = 0; i < 10000; i++) {
            if (count.get() < 100 && count.get() >= 0) { //如果未加锁,之间还会有其他线程插进来
                count.incrementAndGet();
            }
        }
    }

    public static void main(String[] args) {
        T t = new T();
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(t::m, "thread" + i));
        }
        threads.forEach(Thread::start);
        threads.forEach((o) -> {
            try {
                //join()方法阻塞调用此方法的线程,直到线程t完成,此线程再继续。通常用于在main()主线程内,等待其它线程完成再结束main()主线程。
                o.join(); //相当于在main线程中同步o线程,o执行完了,main线程才有执行的机会
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(t.count);
    }
}

问题六

写一个程序,在main线程中启动100个线程,100个线程完成后,主线程打印“完成”

package cn.thread;

import java.util.concurrent.CountDownLatch;

/**
 * 写一个程序,在main线程中启动100个线程,100个线程完成后,主线程打印“完成”
 *
 * @author webrx [webrx@126.com]
 * @version 1.0
 * @since 16
 */
public class T12 {
    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(100);
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                String tn = Thread.currentThread().getName();
                System.out.printf("%s : 开始执行...%n", tn);
                System.out.printf("%s : 执行完成,程序结束。%n", tn);
                latch.countDown();
            }, "T" + i).start();
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("---------------------------------------");
        System.out.println("100个线程执行完了。");
        String tn = Thread.currentThread().getName();
        System.out.printf("%s : 执行完成,程序结束。%n", tn);
    }
}

到此这篇关于高价值Java多线程面试题分析的文章就介绍到这了,更多相关Java 多线程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java多线程面试题(面试官常问)

    进程和线程 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的.系统运行一个程序即是从一个进程从创建.运行到消亡的过程.在Java中,当我们启动main函数时其实就是启动了一个JVM的进程,而mian函数所在的线程就是这个进程中的一个线程,称为主线程. 线程是比进程更小的执行单位.一个进程在其执行的过程中可以产生多个线程.与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程都有自己的程序计数器.虚拟机和本地方法栈,所以系统在产生一个线程,或在各个线程之间切换工作是,

  • Java常见面试题之多线程和高并发详解

    volatile 对 volatile的理解 volatile 是一种轻量级的同步机制. 保证数据可见性 不保证原子性 禁止指令重排序 JMM JMM(Java 内存模型)是一种抽象的概念,描述了一组规则或规范,定义了程序中各个变量的访问方式. JVM运行程序的实体是线程,每个线程创建时 JVM 都会为其创建一个工作内存,是线程的私有数据区域.JMM中规定所有变量都存储在主内存,主内存是共享内存.线程对变量的操作在工作内存中进行,首先将变量从主内存拷贝到工作内存,操作完成后写会主内存.不同线程间

  • 每日六道java新手入门面试题,通往自由的道路--多线程

    目录 1. 你可以讲下进程与线程的区别?为什么要用多线程? 2. 什么是上下文切换? 3. 说说你知道的几种创建线程的方式 4. 昨天你讲到创建线程后使用start方法去调用线程,为什么run方法不行呢?有什么区别? 5. 你知道你开启一个线程后,它的状态有那些吗? 6. 既然讲到超时方法,那你讲下sleep和wait的区别和他们需要怎样唤醒 总结: 1. 你可以讲下进程与线程的区别?为什么要用多线程? 进程:进程是程序的一次执行过程,是系统运行程序的基本单位. 线程:单个进程中执行中每个任务就

  • Java经典面试题汇总--多线程

    目录 1. 并行和并发有什么区别? 2. 线程和进程的区别? 3. 守护线程是什么? 4. 实现多线程的方式有哪些? 5. 说一下 runnable 和 callable 有什么区别? 6. sleep() 和 wait() 有什么区别? 7. 线程有哪些状态? 8. notify()和 notifyAll()有什么区别? 9. 线程的 run() 和 start() 有什么区别? 10. 创建线程池有哪几种方式? 11. 线程池中 submit() 和 execute() 方法有什么区别? 1

  • Java多线程面试题之交替输出问题的实现

    目录 交替输出问题 最简单的解法 面试官想听到的解法 更灵活,更精细的解法 交替输出问题 一定要保证交替输出,这就涉及到两个线程的同步问题. 有人可能会想到,用睡眠时间差来实现,但是只要是多线程里面,线程同步玩sleep()函数的,99.99%都是错的. 这道题其实有100多种解法. 最简单的解法 是这个问题的最优解,但其实不是面试官想听到的答案 关键函数 Locksupport.park():阻塞当前线程Locksupport.unpark(""):唤醒某个线程 LockSuppor

  • 三道java新手入门面试题,通往自由的道路--多线程

    目录 1. 你知道线程安全问题吗? 2. 那如何解决线程安全问题呢? 3. 那你讲下死锁是什么吧? 总结 1. 你知道线程安全问题吗? 线程安全问题:一般指在多线程模式下,多个线程对同一个共享数据进行操作时,第一个线程还没来得及更新共享数据,从而导致另外一个线程没得到最新的数据,并更新数据,从而产生线程安全问题.比较常见的场景有买票. 我举个例子吧: 需求:比如买周杰伦演唱会的门票,此时有三个窗口同时卖总共100张票.窗口就是线程对象,而100张票的资源,此时就相当于多个线程去抢占cpu的资源去

  • 高价值Java多线程面试题分析

    问题一 A线程正在执行一个对象中的同步方法,B线程是否可以同时执行同一个对象中的非同步方法? 可以,两个线程运行所需资源不同,不需要抢占. 案例一. package duoxiancheng2; /** * @author yeqv * @program A2 * @Classname Ms1 * @Date 2022/2/7 19:08 * @Email w16638771062@163.com */ public class Ms1 { //A线程正在执行一个对象中的同步方法,B线程是否可以

  • 15个高级Java多线程面试题及回答

    Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题.在投资银行业务中多线程和并发是一个非常受欢迎的话题,特别是电子交易发展方面相关的.他们会问面试者很多令人混淆的Java线程问题.面试官只是想确信面试者有足够的Java线程与并发方面的知识,因为候选人中有很多只浮于表面.用于直接面向市场交易的高容量和低延时的电子交易系统在本质上是并发的.下面这些是我在不同时间不同地点喜欢问的Jav

  • 15个顶级Java多线程面试题(附答案)

    在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题.在投资银行业务中多线程和并发是一个非常受欢迎的话题,特别是电子交易发展方面相关的.他们会问面试者很多令人混淆的Java线程问题.面试官只是想确信面试者有足够的Java线程与并发方面的知识,因为候选人中有很多只浮于表面.用于直接面向市场交易的高容量和低延时的电子交易系统在本质上是并发的.下面这些是我在不同时间不同地点喜欢问的Java线程问题.我没有提供答

  • 2018版java多线程面试题集合及答案

    java多线程面试题整理及答案,供大家参考,具体内容如下 1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对 运算密集型任务提速.比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒.Java在语言层面对多线程提供了卓越的支 持,它也是一个很好的卖点. 2.线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务.不同的进程使用

  • Java多线程常见案例分析线程池与单例模式及阻塞队列

    目录 一.单例模式 1.饿汉模式 2.懒汉模式(单线程) 3.懒汉模式(多线程) 二.阻塞队列 阻塞队列的实现 生产者消费者模型 三.线程池 1.创建线程池的的方法 (1)ThreadPoolExecutor (2)Executors(快捷创建线程池的API) 2.线程池的工作流程 一.单例模式 设计模式:软件设计模式 是一套被反复使用.多数人知晓.经过分类编目.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.程序的重用性. 单例模式:是设计模式的一种.

  • Java 多线程使用要点分析

    多线程细节问题 sleep方法和wait方法的异同点? 相同点: 让线程处于冻结状态. 不同点: sleep必须指定时间 wait可以指定时间也可以不指定时间 sleep时间到,线程处于临时阻塞状态或者运行态 wait如果没有时间,必须通过notify或者notifyAll唤醒 sleep不一定非要定义在同步中 wait必须定义在同步中 都定义在同步中时 sleep放执行权,不放锁 wait放执行权,放锁 syschronized(obj) { wait();// 0 1 2 code... }

  • java 多线程与并发之volatile详解分析

    目录 CPU.内存.缓存的关系 CPU缓存 什么是CPU缓存 为什么要有多级CPU Cache Java内存模型(Java Memory Model,JMM) JMM导致的并发安全问题 可见性 原子性 有序性 volatile volatile特性 volatile 的实现原理 总结 CPU.内存.缓存的关系 要理解JMM,要先从计算机底层开始,下面是一份大佬的研究报告 计算机在做一些我们平时的基本操作时,需要的响应时间是不一样的!如果我们计算一次a+b所需要的的时间: CPU读取内存获得a,1

  • Java多线程和并发基础面试题(问答形式)

    本文帮助大家掌握Java多线程基础知识来对应日后碰到的问题,具体内容如下 一.Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含了不同的类和程序的单一进程.线程可以被称为轻量级进程.线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源. 2. 多线程编程的好处是什么? 在多线程程序中,多个线程被并发的执行以提高程序的效率,C

随机推荐