JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

Java多线程并发编程问答-No1 多线程同时运行同个子函数

wys521 2024-11-06 20:35:31 精选教程 31 ℃ 0 评论

一.CopyOnWriteArrayList 可以用于什么应用场景?

CopyOnWriteArrayList(免锁容器)的好处之一是当多个迭代器同时遍历和修改这个列表时,不会抛出ConcurrentModificationExceptioin。在CopyOnWriteArrayList中,写入将导致创建整个底层数组的副本,而源数组将保留在原地,使得复制的数组在被修改时,读取操作可以安全地执行。

1.由于写操作的时候,需要拷贝数组,会销毁内存,如果原数组的内容比较多的情况下,可能导致young GC 或者full GC;

2.不能用于实时读的场景,像拷贝数组、新增元素都需要时间,所以调用一个set操作后,读取到数据可能还是旧的,虽然CopyOnWriteArrayList能做到最终一致性,但是还是没法满足实时性的要求;

CopyOnWirteArrayList透露的思想

1.读写分离,读和写分开

2.最终一致性

3.使用另外开辟空间的思路,来解决并发冲突。

二.什么叫线程安全?servlet是线程安全吗?

线程安全是编程中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。

Servlet不是线程安全的,servlet是单实例多线程的,当多个线程同时访问同一个方法,是不能保障共享变量的线程安全性的。

Strus2的action是多实例多线程的,是线程安全的,每个请求过来都会new一个新的action分配给这个请求,请求完成后销毁。

SpringMVC的Controller是线程安全的吗?

不是的,和Servlet和SpringMVC需要考虑线程安全问题,但是性能可以提升不用处理太多的GC,可以使用ThreadLocal来处理多线程的问题。

三.volatile有什么用? 能否用一句话说明下volatile的应用场景?

volatile保证内存可见性和禁止指令重排。

volatile用于多线程环境下的单次操作(单次读或单次写)。

四.为什么代码会重拍下?

在执行程序时,为了提高性能,处理器和编译器常常会对指令进行重排序,但是不能随意重排序,不是你想怎么排序就怎么排序,它需要满足一下两个条件:

1.在单线程环境下不能改变程序运行的结果;

2.存在数据依赖关系的不允许重排序,需要注意的是:重排序不会影响单线程环境的执行结果,但是会破坏多线程的执行语义。

五、Java中wait和sleep方法的不同?

最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

六;Java实现阻塞队列

ArrayBlockingQueue:一个由数组结果组成的有界阻塞队列。

LinkedBlockingQueue:一个由链表结果组成的有界阻塞队列。

PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。

DelayQueue:一个使用优先级队列实现的无界阻塞队列。

SynchronousQueue:一个不存储元素的阻塞队列。

LinkedTransferQueue:一个由链表结果组成的无界阻塞队列。

LinkedBlockingDeque:一个由链表结果组成的双向阻塞队列。

ArrayBlockingQueue:是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当队列可用时,可用按照阻塞的先后顺序访问队列,即先阻塞的生产者线程,可用先往队列里插入元素,先阻塞的消费者线程,可用先从队列里获取元素。通常情况下为了保证公平性会降低吞吐量。

七.一个线程运行时发生异常会怎样?

如果异常没有被捕获该线程将会停止执行。

Thread.UncaughtExceptionHandler是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用Thread.getUncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理。

八.如何在两个线程之间贡献数据?

在两个线程之间共享变量即可实现共享。

一般情况下,共享变量要求变量本身是线程安全的,然后在线程内使用的时候,如果有对共享变量的符合操作,那么也得保证复合操作的线程安全性。

九.为什么wait,notify和notifyAll这些方法不在thread类里面?

一个很明显的原因是Java提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。

十.什么是ThreadLocal变量?

ThreadLocal是Java里面一种特殊的变量。每个线程都有一个ThreadLocal就是每个线程都拥有了自己独立的一个变量,竞争条件被彻底消除了。它是为了创建代价高昂的对象获取线程安全的好方法,比如你可以用ThreadLocal 让SimpleDateFormat变成线程安全的,因为那个类创建代价高昂且每次调用都需要创建不同的实例所以不值得在局部范围内使用它,如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者不变性的情况下获取了线程安全。

十一.Java中interrupted和isInterrupted方法的区别?

interrupt方法用于中断线程。调用该方法的线程状态为将被置为”中断“状态。注意:线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态并处理。支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置于”中断“状态,就会抛出中断异常。

interrupted 查询当前线程的中断状态,并且清除原状态。如果一个线程被中断了,第一次调用interrupted则返回true,第二次和后面的就返回false了。

isInterrupted 仅仅是查询当前线程的中断状态。

十二.为什么wait和notify方法要在同步块中调用?

Java API 强制要求这样做,如果不这么做,代码就会抛出 IllegalMonitorStateException异常。

还有一个原因是为了避免wait和notify之间产生竞争条件。

十三.为什么应该在循环中检查等待条件?

处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。

十四.Java中的同步集合与并发集合有什么区别?

同步集合与并发集合都是为了多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。

在Java1.5之前只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的扩展性。

Java1.5介绍了并发集合ConcurrentHashMap,不仅提供了线程安全还用锁分离和内部分区等现代技术提供了扩展性。

十五.什么是线程池?为什么要使用线程池?

创建线程需要花费昂贵的资源和时间,如果任务来了创建线程那么响应时间会变长,而且一个线程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫做工作线程。

从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。

十六.怎么检测一个线程是否拥有锁?

在java.lang.Thread中有一个方法叫做holdsLock(),它返回ture如果当且仅 当且线程拥有某个具体对象的锁。

十七.如何在Java中获取线程堆栈?

kill -3 [java pid]

不会在当前线程输出,它会输出到代码执行的或指定的地方去。

比如,kill -3 tomcat pid,输出堆栈到log目录下。

jstack [java pid]

这个比较简单,在当前终端显示,也可以重定向到指定文件中。

-JvisualVM:Thread Dump

打开JvisualVM后,都是界面操作,过程还是很简单的。

十八.JVM中哪些参数是用来控制线程的栈大小的?

-Xss每个线程的栈大小

十九.Thread类中的yield方法有什么作用?

使当前线程从执行从执行状态(运行状态)变为可执行态(就绪状态)。

当前线程到了就绪状态,那么接下来哪个线程会从就绪状态变为执行状态呢?可能是当前线程,也可能是其他线程,看系统的分配了。

二十.Java中ConcurrentHashMap的并发度是什么?

ConcurrentHashMap把实际Map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样在多线程情况下就能避免争用。

在JDK1.8后,它屏蔽了Segment(锁段)的概念,而是启用了一种全新的方式实现,利用CAS算法。同时加入了更多的辅助变量来提高并发度。

二十一.Java中Semaphore是什么?

Java中的Semaphore是一种新的同步类,它是一个技术信号。从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每个acquire(),然后再后去许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动。信号量常常用于多线程的代码中,比如数据库连接池。

二十二.线程池中sumit()和execute()方法有什么区别?

两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中。

而sumit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其他线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表