1.java中实现多线程有几种方式
继承Thread类;
实现Runnable接口;
实现Callable接口通过FutureTask 包装器来创建Thread线程;
使用ExecutorService、Callable、Future实现由返回结果的多线程(也就是使用ExecutorService来管理前面的三种方式)。
2.如何停止一个正在运行的线程
1.使用退出标志,是线程正常退出。也就是当run方法完成后线程终止。
2.stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume这样都是过期作废的方法。
3.使用intereupt方法中断线程。
3.notify()和notifyAll()有什么区别
notify可能会导致死锁,而notifyAll则不会
任何时候只有一个线程可以或得锁,也就是只有一个线程可以运行synchronize中的代码
使用notifyAll,可以唤醒所有处于wait状态的线程,使其重新进入锁的争夺队列中,而notify只能唤醒一个。
wait()因配合while循环使用,不应使用if,务必在wait()调用前后都检查条件,如果不满足,必须调用notify()
唤醒另外的线程来处理,自己继续wait()直接条件满足在往下执行。
notify()是对notifyAll()的一个优化,但它有很精确的应用场景,并且要求正确使用。不然可能导致死锁。正确的场景应该是WaitSet中等待的是相同的条件,唤醒任意一个都能正确处理接下来的事项,如果唤醒的线程无法正确处理,务必确保继续notify()下一个线程,并且自身需要重新回到WaitSet中。
4.sleep()和wait()有什么区别
对于sleep()方法。我们首先要知道该方法是属于Thread类中的,而wait()方法,则属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出CPU该其它线程,但是他的监控状态依然保持着。当指定的时间到了有自动恢复运行状态。在调用sleep()方法的过程中**,线程不会释放对象锁。**
当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。
5.volatile是什么?可以保证有序性吗?
一旦一个共享变量被volatile修饰后,那么久具备了两层语义:
1.保证了不同线程对这个变量进行操作时的可见性。就是一个线程修改了某个变量的值,这个心新值对其它线程是可见的,volatile会强制将修改的值立即写入主存。
2.禁止进行指令重排序。
volatile操作不是原子性操作
什么叫保证部分有序性?
当程序执行到volatile变量的读操作和写操作是,其前面的操作必定全部完成,且结果已经对后面的操作可见,其后面的操作肯定没有执行。
重拍序只能保证自己的顺序不变。
volatile一般用于,状态标记量和单例模式的双检锁。
6.Thread类中的start()和run()方法有什么区别?
start()方法被用来创建多线程,而start()内部调用了run()方法,这和直接调用run()方法的效果不一样。
当你调用run()方法的时候,只会是原来的线程中调用,没有启动新的线程。start()方法才会启用新的线程。
7.为什么wait,notify和notifyall这些方法不在Thread类里
明显的原因是java提供的锁是对象级的而不是线程级的,每个对象都有锁,用过线程获得。如果线程需要等待某些锁那么调用对象的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。由于wait、notify和notifyall都是锁级别的操作。所以把他们定义在object类中,因为锁属于对象。
8为什么wait和notify方法要在同步块中调用?
1.是有在调用线程拥有的某个对象的独占锁时,才能够调用对象的wait(),notity()和notifyall()方法。
2.代码会抛异常
3.为了避免wait和notify之间产生竞态条件。
wait方法强制当前线程释放对象锁。调用wait方法前,当前线程必须已经获得对象锁。因此才必须在同步块中使用wait()方法
调用notify和notifyall方法之前,调用的线程必须已经得到对象的锁,所以也必须在同步块中使用。
调用wait()方法的原因是:调用线程希望某一个特殊的状态被设置之后再继续执行,调用notify和notifyall的原因是,调用线程希望告诉其他等待中线程:“特殊状态已经被设置”。
9.java中interrupted和isInterrupted方法的区别?
interrupted 的会将中断状态清除,而isInterrupted方法不会。
10.synchronized和reentrantlock有什么不同?
相似点
加锁方式同步,都是阻塞是的同步。就是说一下线程获得对象锁,进入到同步块中,其他访问该同步块的线程必须阻塞在同步块外等待。进行线程阻塞和唤醒的代价是非常高的。
区别:
synchronized是java语言的关键字,是原生语法层面的互斥,需要jvm实现。reentrantlock他是jdk1.5之后提供的API层面的互斥锁。需要lock()和unlock()方法配合try/finally语句来完成
11.如何保证线程的顺序
使用Join()方法在一个线程中启动另一个线程,另外一个线程完成该线程才会继续执行。先启动最后一个,最后调用第一个执行的线程。
12.synchronizedMap和ConcurrentHashMap有什么区别
synchronizedMap和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步。ConcurrentHashMap的实现更加精细。它对map中的所有桶加了锁。所以只要有一个线程访问map,其它线程就无法进入map。如果一个线程在方法ConcurrentHashMap某个桶时,其它线程任然可以对map进行操作。
ConcurrentHashMap在性能和安全性方面,明显比synchronizedMap更加有优势。
13.什么是线程安全
线程的安全就是多线程访同一代码,会产生不确定的结果。
在多线程环境中,当个线程不共享数据的时候,那么线程是安全的。单这种情况并不多见,对数情况下需要共享数据,这时就需要进行适当的同步控制了。
一般涉及到synchronized,就是同一段的代码同时只能有一个线程来操作。
14 常用的线程池
newSingleThreadExecutor:创建一个单线程的线程池。
newFixedThreadpool:创建固定大小的线程池
newCachedThreadPool:创建一个可缓存的线程池
newScheduledThreadPool:创建一个无限大小的线程池。