多线程面试知识点

线程之间的通信

1.为什么要线程通信 多个线程并发执行时,默认情况下cpu是随机切换线程的,当我们需要多个线程共同完成一件任务并且希望他们有规律的执行,那么多线程之间就需要一些协调通信,以此来让我们达到多线程共同操作一份数据。 如果我们没有使用线程通信,也可以实现,但是很大程度上会造成多个线程对一个资源的争夺,那样可能会造成错误和损失。 2.什么线程通信 等待唤醒机制 wait(); notify();

什么是守护线程

当jvm中不存在任何一个正在运行的非守护线程时,jvm就会退出。
守护线程可以自动结束自己的生命周期。
如果jvm要退出时,由于垃圾回收线程还在运行着,导致程序无法退出,这是很不合适的。所以守护线程常常被用作执行一些后台任务,你希望退出能够自动关闭的。

为什么有了进程还要线程

因为在一些情况下,进程是有很多缺陷的。1.进程只能在同一时间干一件事,不能同时干两件事。2.进程在执行的过程中如果阻塞,比如等待输入,那么整个进程都会被挂起,即使有些工作不依赖输入。

可重入锁的理解

ReentrantLock实现了Lock接口 当前持有这个锁的线程可以重复锁定,锁的状态+1;但是要在try catch 的finally里unlock,每次unlock锁的状态–;为0释放锁。

线程组

java中用线程组管理一批线程,对线程组做的操作相当于对里面所有的下次都做了同样的事情。同一个线程组的线程是可以相互修改对方数据的。。
为什么不推荐:1.线程组比较有意义的几个函数 stop resume suspend ,由于会导致死锁所以被废掉了,这样线程组的价值就大打折扣了。2.线程组不是线程安全的,在使用过程中得到的信息并不是及时有效的。

什么是乐观锁,什么是悲观锁

悲观锁就是总是假设最坏的情况,每次去拿数据都会认为别的线程会对其进行修改,所以每次都会上锁,这样别人想要拿这个数据只能等它释放锁。传统的关系型数据库中,行锁,表锁,读锁和写锁都是悲观锁,synchronized也是悲观锁。乐观锁,总是假设最好的情况,拿数据认为别人不会去修改,所以不上锁,但是更新的时候还是回去判断一下在这期间有没有线程对其进行修改。CAS就是乐观锁。

java的线程调度算法是什么

抢占式,操作系统根据线程的优先级和饥饿程度算出一个总的优先级,并且分配一个时间片给某个线程执行。

同步块和同步方法哪个更好

同步块更好,因为同步块只会锁住指定的那个对象。而同步方法则会锁住整个当前这个类对象,类中所有方法上有sych的都会被锁住,及时他们没有任何关系。

Run() 和Start()的区别

通过start()方法可以调用run()方法达到多线程的目的。通常,系统通过调用线程类的start方法来启动一个线程,此时线程处于就绪状态,而非运行状态,这也就意味着这个线程可以被jvm来调度执行,在调度过程中,jvm会调用线程类的run方法来完成实际的操作,当run方法结束后,线程就终结。如果直接调用run方法,它只会被当作一个普通方法执行,程序只有主线程一个线程。并没有达到多线程的目的。
如何控制某个方法允许兵法访问线程的个数
可以使用semaphore信号量

public class 信号量 {
static Semaphore semaphore=new Semaphore(5,true);
public static void main(String[] args) {for (int i=0;i<100;i++) {new Thread(new Runnable() {@Overridepublic void run() {test();}}).start();}
}public static void test(){try {semaphore.acquire();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("进来了");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("走了");semaphore.release();
}

为什么wait和notify定义在object类中

因为java提供的锁是对象级别的,不是线程级别的。如果方法在线程类里,就会不知道等待的锁是哪个。而wait和notify是锁级别的方法,当然放在object类里了

关于NIO的学习

NIO主要有三大核心部分:channel(通道),buffer(缓存区),selector。NIO基于Channel和Selector进行操作,数据总是从通道读取到缓存区,或者从缓存区读到通道中。Selector用于监听多个通道的时间(比如:连接打开,数据到达)。单个线程可以监听多个数据通道。
和传统io区别最大的地方在于io时面向流的,nio是面向缓存区的。还有就是io的各种流是阻塞的,意思就是,一个线程调用read或write的时候,线程被阻塞,等到读或写完才可以接着运行。而nio是非阻塞的。
Channel
FileChannelDatagramChannelSocketChannelServerSorketChannel

Callable 和Runnable的区别

Runnabel里面只是声明了run方法,时void 没有返回值。Callable里面是这样的
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * * @throws Exception if unable to compute a result * */ * V call() throws Exception;}
* 是一个泛型接口,call方法是有返回值的。
future 就是对于具体的Runnabl或者Callable任务的执行结果进行取消,查询是否完成,获取结果。

Synchronized和lock的区别

1.Sync是java内置的关键字,而lock是个java类2.sync无法判断线程是否获取锁的状态,lock可以3.sync会自动释放锁,而lock需要在finally里主动释放4.使用sync的两个线程,如果一个没执行完,另一个就不能执行,一直等待。lock如果拿不到就会直接结束。(tryLock)5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)

CountDownLacth 和CyclicBarrier的区别

1.CoutDownLacth一般是一个线程等待其他线程执行完以后。2.CyclicBarrier是一组线程互相等待至某个状态,然后再同时执行。3.CountDownLacth不可重用,但是CyclicBarier可以。

CopyOnWriteArrayList

copyOnWrite即写时复制的容器。通俗的理解就是,每次修改都会创建一个新的容器,将原容器复制到新容器,在新的容器修改后,将原容器的引用指向新的容器。这样我们在并发的读的时候,就不需要加锁了。
但是修改还是要枷锁的。

什么是忙循环

忙循环就是程序员用循环让一个线程等待,而不是用sleep,wait,yield,他们都放弃了cpu控制,而忙循环没有。这么做是·为了保留cpu缓存。
如何检测一个线程有没有锁
线程类里有holdsLock这个方法。

产生死锁的四个必要条件

1.互斥条件2.不可剥夺3.请求和保持4.循环等待

线程池的一些学习

概念
线程时稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,和理的使用线程池对线程进行统一的分配,调优,监控,有以下好处:

1.降低资源消耗2.提高响应3提高线程的可管理性
内部实现

public ThreadPoolExecutor(int corePoolSize, // 核心线程数int maximumPoolSize, // 最大线程数long keepAliveTime, // 线程存活时间(在 corePore<*<maxPoolSize 情况下有用)TimeUnit unit, // 存活时间的时间单位BlockingQueue<Runnable> workQueue // 阻塞队列(用来保存等待被执行的任务)ThreadFactory threadFactory, // 线程工厂,主要用来创建线程;RejectedExecutionHandler handler // 当拒绝处理任务时的策略){this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}

线程池工作原理线程中的核心线程数,当提交一个任务时,如果线程池中的线程小于核心线程数,那么就创建一个线程执行该任务。当线程数等于核心线程数时就放到阻塞队列里,如果阻塞队列也满了,就继续创建线程执行当前任务,知道线程池中的数据达到最大线程数。再有线程来就只能执行reject()处理任务。
excute和submit的区别
1.接收的参数不同
2.submit有返回值,而excute没有
3.submit方便Exception处理如果你在你的任务里会抛出checked或者unchecked expception,而你又希望外面的调用者能够感知这些异常并能够及时的处理,那么就需要用到submit通过捕获Furture.get()抛出的异常。

线程池的种类
1.CachedThreadPool 可缓存线程池,如果线程池的长度超过处理的需求,就可以灵活的回收空闲的线程,如无可回收,就新建线程。
2.FixThreadPool 定长的线程池,可控制线程的最大并发数,超过的线程会在队列里等待。3.ScheduledThreadPool 定长的线程池,支持定时已及周期性任务执行。
4SingleTreadExcutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
计算线程池的最优大小cpu数量*cpu使用率(1+等待时间/计算时间)

interruped()和isInterrupted的区别

当线程调用Thread.interrupt的时候,线程的中断表示会置为true。当调用interrupted是,中断标示会被清除,而isInterrupted只会查询标示状态而不会清除标示。任何抛出InterruptedException异常的方法都会将中断状态清零。
为什么simpleDateFormat不是线程安全的因为DateFormat进行日期转换实际上是里面的Calender来实现的,但是再parse的最后是把Calender清理了,这时候再来新的一条数据,就会出现线程安全问题。

https://blog.csdn.net/Ybulingbuling/article/details/99717708
https://github.com/qq1015004506/2019_campus_apply

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值