广告
返回顶部
首页 > 资讯 > 精选 >Android的线程、多线程和线程池面试题有哪些
  • 861
分享到

Android的线程、多线程和线程池面试题有哪些

2023-06-04 23:06:50 861人浏览 泡泡鱼
摘要

这篇“Android的线程、多线程和线程池面试题有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android的线程、多

这篇“Android线程多线程线程池面试题有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android的线程、多线程和线程池面试题有哪些”文章吧。

1、开启线程的三种方式?

1)继承Thread类,重写run()方法,在run()方法体中编写要完成的任务 new Thread().start();

2)实现Runnable接口,实现run()方法 new Thread(new MyRunnable()).start();

3)实现Callable接口MyCallable类,实现call()方法,使用FutureTask类来包装Callable对象,使用FutureTask对象作为Thread对象的target创建并启动线程;调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

FutureTask<Integer> ft = new FutureTask<Integer>(new MyCallable());new Thread(ft).start();

2、run()和start()方法区别

run()方法只是线程的主体方法,和普通方法一样,不会创建新的线程。
只有调用start()方法,才会启动一个新的线程,新线程才会调用run()方法,线程才会开始执行。

3、如何控制某个方法允许并发访问线程的个数?

创建Semaphore变量,Semaphore semaphore = new Semaphore(5, true);当方法进入时,请求一个信号,如果信号被用完则等待,方法运行完,释放一个信号,释放的信号新的线程就可以使用。

4、在Java中wait和seelp方法的不同

wait()方法属于Object类,调用该方法时,线程会放弃对象,只有该对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

sleep()方法属于Thread类,sleep()导致程序暂停执行指定的时间,让出CPU,但它的监控状态依然保存着,当指定时间到了又会回到运行状态,sleep()方法中线程不会释放对象锁。

5、谈谈wait/notify关键字的理解

notify:
唤醒在此对象监视器上等待的单个线程

notifyAll():
通知所有等待该竞争资源的线程

wait:
释放obj的锁,导致当前的线程等待,直接其他线程调用此对象的notify()notifyAll()方法

当要调用wait()notify()/notifyAll()方法时,一定要对竞争资源进行加锁,一般放到synchronized(obj)代码中。当调用obj.notify/notifyAll后,调用线程依旧持有obj锁,因此等待线程虽被唤醒,但仍无法获得obj锁,直到调用线程退出synchronized块,释放obj锁后,其他等待线程才有机会获得锁继续执行。

6、什么导致线程阻塞?

(1)一般线程阻塞

1)线程执行了Thread.sleep(int millsecond)方法,放弃CPU,睡眠一段时间,一段时间过后恢复执行;

2)线程执行一段同步代码,但无法获得相关的同步锁,只能进入阻塞状态,等到获取到同步锁,才能恢复执行;

3)线程执行了一个对象的wait()方法,直接进入阻塞态,等待其他线程执行notify()/notifyAll()操作;

4)线程执行某些io操作,因为等待相关资源而进入了阻塞态,如System.in,但没有收到键盘的输入,则进入阻塞态。

5)线程礼让,Thread.yield()方法,暂停当前正在执行的线程对象,把执行机会让给相同或更高优先级的线程,但并不会使线程进入阻塞态,线程仍处于可执行态,随时可能再次分得CPU时间。线程自闭,join()方法,在当前线程调用另一个线程的join()方法,则当前线程进入阻塞态,直到另一个线程运行结束,当前线程再由阻塞转为就绪态。

6)线程执行suspend()使线程进入阻塞态,必须resume()方法被调用,才能使线程重新进入可执行状态。

7、线程如何关闭?

  1. 使用标志位

2)使用stop()方法,但该方法就像关掉电脑电源一样,可能会发生预料不到的问题

3)使用中断interrupt()

public class Thread {    // 中断当前线程    public void interrupt();    // 判断当前线程是否被中断    public boolen isInterrupt();    // 清除当前线程的中断状态,并返回之前的值    public static boolen interrupted();   }

但调用interrupt()方法只是传递中断请求消息,并不代表要立马停止目标线程。

8、讲一下java中的同步的方法

之所以需要同步,因为在多线程并发控制,当多个线程同时操作一个可共享的资源时,如果没有采取同步机制,将会导致数据不准确,因此需要加入同步锁,确保在该线程没有完成操作前被其他线程调用,从而保证该变量的唯一一性和准确性。

1)synchronized修饰同步代码块或方法

由于java的每个对象都有一个内置锁,用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需获得内置锁,否则就处于阴塞状态。

2)volatile修饰变量

保证变量在线程间的可见性,每次线程要访问volatile修饰的变量时都从内存中读取,而不缓存中,这样每个线程访问到的变量都是一样的。且使用内存屏障。

3)ReentrantLock重入锁,它常用的方法有ReentrantLock():

创建一个ReentrantLock实例

lock()获得锁unlock()释放锁

4)使用局部变量ThreadLocal实现线程同步

每个线程都会保存一份该变量的副本,副本之间相互独立,这样每个线程都可以随意修改自己的副本,而不影响其他线程。常用方法ThreadLocal()创建一个线程本地变量;get()返回此线程局部的当前线程副本变量;initialValue()返回此线程局部变量的当前线程的初始值;set(T value)将此线程变量的当前线程副本中的值设置为value

5) 使用原子变量

AtomicInteger,常用方法AtomicInteger(int value)创建个有给定初始值的AtomicInteger整数;addAndGet(int data)以原子方式将给定值与当前值相加

6)使用阻塞队列实现线程同步

例如LinkedBlockingQueue<E>

9、如何保证线程安全

线程安全性体现在三方法:

1)原子性:

提供互斥访问,同一时刻只能有一个线和至数据进行操作。

jdk中提供了很多atomic类,如AtomicInteger\AtomicBoolean\AtomicLong,它们是通过CAS完成原子性。
JDK提供锁分为两种:synchronized依赖JVM实现锁,该关键字作用对象的作用范围内同一时刻只能有一个线程进行操作。另一种LOCK,是JDK提供的代码层面的锁,依赖CPU指令,代表性是ReentrantLock

2)可见性:

一个线程对主内存的修改及时被其他线程看到。

JVM提供了synchronizedvolatilevolatile的可见性是通过内存屏障和禁止重排序实现的,volatile会在写操作时,在写操作后加一条store屏障指令,将本地内存中的共享变量值刷新到主内存;会在读操作时,在读操作前加一条load指令,从内存中读取共享变量。

3)有序性:

指令没有被编译器重排序。

可通过volatile、synchronized、Lock保证有序性。

10、两个进程同时要求写或者读,能不能实现?如何防止进程的同步?

我认为可以实现,比如两个进程都读取日历进程数据是没有问题,但同时写,应该会有冲突。

可以使用共享内存实现进程间数据共享。

11、线程间操作List

多线程数量的问题,一般情况下,多线程数量要等于机器CPU核数-1.

1.如何让n个线程顺序遍历含有n个元素的List集合
import java.util.ArrayList;import java.util.List;import org.apache.commons.lang3.ArrayUtils;public class Test_4 {        public synchronized void handleList(List<String> data, int threadNum) {        int length = data.size();        int tl = length % threadNum == 0 ? length / threadNum : (length                / threadNum + 1);        for (int i = 0; i < threadNum; i++) {            int end = (i + 1) * tl;            HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ",  data, i * tl, end > length ? length : end);            thread.start();        }    }    class HandleThread extends Thread {        private String threadName;        private List<String> data;        private int start;        private int end;        public HandleThread(String threadName, List<String> data, int start, int end) {            this.threadName = threadName;            this.data = data;            this.start = start;            this.end = end;        }        public void run() {            List<String> subList = data.subList(start, end);            System.out.println(threadName+"处理了"+subList.size()+"条!");        }    }    public static void main(String[] args) {        Test_4 test = new Test_4();        // 准备数据        List<String> data = new ArrayList<String>();        for (int i = 0; i < 6666; i++) {            data.add("item" + i);        }        test.handleList(data, 5);        System.out.println(ArrayUtils.toString(data));    }}
2. List多线程并发读取读取现有的list对象
//测试读取List的线程类,大概34秒package com.thread.list;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class Main {    public static void main(String[] args) {        List<String> list = new ArrayList<String>();        Map<Long,Integer> map = new HashMap<Long,Integer>();        for(int i = 0;i<1000;i++){            list.add(""+i);        }        int pcount = Runtime.getRuntime().availableProcessors();                long start = System.currentTimeMillis();                for(int i=0;i<pcount;i++){           Thread t = new MyThread1(list,map);            map.put(t.getId(),Integer.valueOf(i));            t.start();            try {                t.join();            } catch (InterruptedException e) {                              e.printStackTrace();            }                       // System.out.println(list.get(i));        }                System.out.println("----"+(System.currentTimeMillis() - start));    }    }//线程类package com.thread.list;import java.util.List;import java.util.Map;public class MyThread1 extends Thread {    private List<String> list;    private Map<Long,Integer> map;    public MyThread1(List<String> list,Map<Long,Integer> map){        this.list = list;        this.map = map;    }    @Override    public void run() {        int pcount = Runtime.getRuntime().availableProcessors();        int i = map.get(Thread.currentThread().getId());        for(;i<list.size();i+=pcount){            System.out.println(list.get(i));        }                  }    }
3.多线程分段处理List集合

场景:大数据List集合,需要对List集合中的数据同标准库中数据进行对比,生成新增,更新,取消数据
解决方案:

List集合分段,
动态创建线程池newFixedThreadPool
将对比操作在多线程中实现

public static void main(String[] args) throws Exception {        // 开始时间        long start = System.currentTimeMillis();        List<String> list = new ArrayList<String>();        for (int i = 1; i <= 3000; i++) {            list.add(i + "");        }        // 每500条数据开启一条线程        int threadSize = 500;        // 总数据条数        int dataSize = list.size();        // 线程数        int threadNum = dataSize / threadSize + 1;        // 定义标记,过滤threadNum为整数        boolean special = dataSize % threadSize == 0;        // 创建一个线程池        ExecutorService exec = Executors.newFixedThreadPool(threadNum);        // 定义一个任务集合        List<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>();        Callable<Integer> task = null;        List<String> cutList = null;        // 确定每条线程的数据        for (int i = 0; i < threadNum; i++) {            if (i == threadNum - 1) {                if (special) {                    break;                }                cutList = list.subList(threadSize * i, dataSize);            } else {                cutList = list.subList(threadSize * i, threadSize * (i + 1));            }            // System.out.println("第" + (i + 1) + "组:" + cutList.toString());            final List<String> listStr = cutList;            task = new Callable<Integer>() {                @Override                public Integer call() throws Exception {                    System.out.println(Thread.currentThread().getName() + "线程:" + listStr);                    return 1;                }            };            // 这里提交的任务容器列表和返回的Future列表存在顺序对应的关系            tasks.add(task);        }        List<Future<Integer>> results = exec.invokeAll(tasks);        for (Future<Integer> future : results) {            System.out.println(future.get());        }        // 关闭线程池        exec.shutdown();        System.out.println("线程任务执行结束");        System.err.println("执行任务消耗了 :" + (System.currentTimeMillis() - start) + "毫秒");    }

12、Java中对象的生命周期

1)创建阶段(Created):

为对象分配存储空间,开始构造对象,从超类到子类对static成员初始化;超类成员变量按顺序初始化,递归调用超类的构造方法,子类成员变量按顺序初始化,子类构造方法调用。

2)应用阶段(In Use):

对象至少被一个强引用持有着。

3)不可见阶段(Invisible):

程序运行已超出对象作用域

4)不可达阶段(Unreachable):

该对象不再被强引用所持有

5)收集阶段(Collected):

假设该对象重写了finalize()方法且未执行过,会去执行该方法。

6)终结阶段(Finalized):

对象运行完finalize()方法仍处于不可达状态,等待垃圾回收器对该对象空间进行回收。

7)对象空间重新分配阶段(De-allocated):

垃圾回收器对该对象所占用的内存空间进行回收或再分配,该对象彻底消失。

13、static synchronized 方法的多线程访问和作用

static synchronized控制的是类的所有实例访问,不管new了多少对象,只有一份,所以对该类的所有对象都加了锁。限制多线程中该类的所有实例同时访问JVM中该类对应的代码。

14、同一个类里面两个synchronized方法,两个线程同时访问的问题

如果synchronized修饰的是静态方法,锁的是当前类的class对象,进入同步代码前要获得当前类对象的锁;

普通方法,锁的是当前实例对象,进入同步代码前要获得的是当前实例的锁;

同步代码块,锁的是括号里面的对象,对给定的对象加锁,进入同步代码块库前要获得给定对象锁;

如果两个线程访问同一个对象的synchronized方法,会出现竞争,如果是不同对象,则不会相互影响。

15、volatile的原理

volatile变量修饰的共享变量进行写操作的时候会多一条汇编代码,lock addl $0x0,lock前缀的指令在多核处理器下会将当前处理器缓存行的数据会写回到系统内存,这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效。同时lock前缀也相当于一个内存屏障,对内存操作顺序进行了限制。

16、synchronized原理

synchronized通过对象的对象头(markWord)来实现锁机制,java每个对象都有对象头,都可以为synchronized实现提供基础,都可以作为锁对象,在字节码层面synchronized块是通过插入monitorenter monitorexit完成同步的。持有monitor对象,通过进入、退出这个Monitor对象来实现锁机制。

17、谈谈NIO的理解

NIO( New Input/ Output)引入了一种基于通道和缓冲区的I/O方式,它可以使用 Native函数库直接分配堆外内存,然后通过一个存储在Java 堆的 DirectByteBuffer对象作为这块内存的引用进行操作,避免了在Java 堆和Native堆中来回复制数据。 NIO是一种同步非阻塞的 IO模型。同步是指线程不断轮询IO事件是否就绪,非阻塞是指线程在等待IO 的时候,可以同时做其他任务。同步的核心就是Selector,Selector代替了线程本身轮询IO事件,避免了阻塞同时减少了不必要的线程消耗;非阻塞的核心就是通道和缓冲区,当IO事件就绪时,可以通过写道缓冲区,保证IO的成功,而无需线程阻塞式地等待。

18.ReentrantLock 、Lock、synchronized和volatile比较

1)volatile:

解决变量在多个线程间的可见性,但不能保证原子性,只能用于修饰变量,不会发生阻塞。volatile能屏蔽编译指令重排,不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面。多用于并行计算的单例模式。volatile规定CPU每次都必须从内存读取数据,不能从CPU缓存中读取,保证了多线程在多CPU计算中永远拿到的都是最新的值。

2)synchronized:

互斥锁,操作互斥,并发线程过来,串行获得锁,串行执行代码。解决的是多个线程间访问共享资源的同步性,可保证原子性,也可间接保证可见性,因为它会将私有内存和公有内存中的数据做同步。可用来修饰方法、代码块。会出现阻塞。synchronized发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生。非公平锁,每次都是相互争抢资源。

3)lock

是一个接口,而synchronizedjava中的关键字,synchronized是内置语言的实现。lock可以让等待锁的线程响应中断。在发生异常时,如果没有主动通过unLock()去释放锁,则可能造成死锁现象,因此使用Lock时需要在finally块中释放锁。

4)ReentrantLock

可重入锁,锁的分配机制是基于线程的分配,而不是基于方法调用的分配。ReentrantLocktryLock方法,如果锁被其他线程持有,返回false,可避免形成死锁。对代码加锁的颗粒会更小,更节省资源,提高代码性能。ReentrantLock可实现公平锁和非公平锁,公平锁就是先来的先获取资源。ReentrantReadWriteLock用于读多写少的场合,且读不需要互斥场景。

以上就是关于“Android的线程、多线程和线程池面试题有哪些”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网精选频道。

--结束END--

本文标题: Android的线程、多线程和线程池面试题有哪些

本文链接: https://www.lsjlt.com/news/240374.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android的线程、多线程和线程池面试题有哪些
    这篇“Android的线程、多线程和线程池面试题有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android的线程、多...
    99+
    2023-06-04
  • Java中多线程面试题有哪些
    这篇文章将为大家详细讲解有关Java中多线程面试题有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。进程和线程进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是从...
    99+
    2023-06-14
  • JAVA有哪些常见的多线程面试题
    本文小编为大家详细介绍“JAVA有哪些常见的多线程面试题”,内容详细,步骤清晰,细节处理妥当,希望这篇“JAVA有哪些常见的多线程面试题”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。什么是线程线程是操作系统能够进...
    99+
    2023-06-04
  • Android中的线程和线程池有什么作用
    今天小编给大家分享一下Android中的线程和线程池有什么作用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前言从用途上来说...
    99+
    2023-07-04
  • java多线程面试题目
    什么是线程?线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。 (推荐学习:java面试题目)比如,如果一个线程完成一个...
    99+
    2020-08-31
    java面试题 java
  • java线程池有哪些
    java的线程池有:1.newCachedThreadPool,线程数量不定的线程池;2.newFixedThreadPool,指定工作线程数量的线程池;3.newScheduledThreadPool,核心线程数量是固定的线程池;4.ne...
    99+
    2022-10-25
  • Java的线程池有哪些
    这篇文章主要讲解了“Java的线程池有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java的线程池有哪些”吧!线程池简介 线程池的概念:线程池就是首先创建一些线程,它们的集合...
    99+
    2023-06-02
  • java基础中并发多线程面试题有哪些
    java基础中并发多线程面试题有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。01 什么是线程线程是操作系统...
    99+
    2022-10-19
  • Java线程面试题的知识点有哪些
    本篇内容主要讲解“Java线程面试题的知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java线程面试题的知识点有哪些”吧!一、sychronied 修饰普通方法和静态方法的区别?什么...
    99+
    2023-07-02
  • 浅谈Android 的线程和线程池的使用
    Android 的线程和线程池从用途上分,线程分为主线程和子线程;主线程主要处理和界面相关的事情,子线程则往往用于耗时操作。主线程和子线程主线程是指进程所拥有的线程。Android 中主线程交 UI 线程,主要作用是运行四大组件以及处理它们...
    99+
    2023-05-30
    android 线程池 roi
  • Java线程池高频面试题总结
    目录1、在启动线程时,为什么要通过调用方法start执行方法run,而不能直接执行方法run?2、方法sleep、join和yield的区别有哪些?3.为什么方法wait、notif...
    99+
    2022-11-12
  • Android创建线程池的方式有哪些
    在Android中,可以使用以下方式创建线程池:1. 使用ThreadPoolExecutor类:可以通过new ThreadPoo...
    99+
    2023-10-18
    Android
  • java的多线程常见面试题
    并行和并发有什么区别? (推荐学习:java常见面试题)并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。...
    99+
    2018-11-10
    java面试题 java
  • Java多线程面试题(面试官常问)
    进程和线程 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是从一个进程从创建、运行到消亡的过程。在Java中,当我们启动main函数时其实...
    99+
    2022-11-12
  • java线程池使用及原理面试题
    目录引导语1、说说你对线程池的理解?2、ThreadPoolExecutor、Executor、ExecutorService、Runnable、Callable、FutureTas...
    99+
    2022-11-13
  • python面试题之python多线程与
    多线程可以共享全局变量,多进程不能 多线程中,所有子线程的进程号相同,多进程中,不同的子进程进程号不同   线程共享内存空间;进程的内存是独立的 同一个进程的线程之间可以直接交流;两个进程想通信,必须通过一个中间代理来实现 创建新线程...
    99+
    2023-01-31
    多线程 面试题 python
  • python面试题之python下多线程
    python多线程有个全局解释器锁(global interpreter lock)。 这个锁的意思是任一时间只能有一个线程使用解释器,跟单cpu跑多个程序一个意思,大家都是轮着用的,这叫“并发”,不是“并行”。 多进程间共享数据,可以使...
    99+
    2023-01-30
    多线程 面试题 python
  • Python中多线程和线程池的使用方法
    Python是一种高级编程语言,它在众多编程语言中,拥有极高的人气和使用率。Python中的多线程和线程池是其强大的功能之一,可以让我们更加高效地利用CPU资源,提高程序的运行速度。本篇博客将介绍Py...
    99+
    2023-10-12
    python
  • java线程池会出现的问题有哪些
    Java线程池在使用过程中可能会遇到以下问题: 资源耗尽:如果线程池中的线程过多,可能会导致系统资源(如内存、CPU)耗尽,从而...
    99+
    2023-10-25
    java
  • Java中Executors有哪些线程池
    本篇文章给大家分享的是有关Java中Executors有哪些线程池,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。java基本数据类型有哪些Java的基本数据类型分为:1、整数类...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作