1. 以下哪几种方式可用来实现线程间通知和唤醒:( )
-
A Object.wait/notify/notifyAll
-
B ReentrantLock.wait/notify/notifyAll
-
C Condition.await/signal/signalAll
-
D Thread.wait/notify/notifyAll
正确答案:A C
题解:
wait()、notify()、和notifyAll()是Object类中的方法
从这三个方法的文字描述可以知道一下几点信息
1. wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
2. 调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
3. 调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程
4. 调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程
为什么这三个不是Thread类声明中的方法,而是Object类中的声明方法
(当然由于Thread类继承了Object类,所以Thread也可以调用这三个方法),其实这个问题很简答,由于每个对象都有monitor(即锁),所以让当前线程等待某个对象的锁,当然通过这个对象来操作了。而不是当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。
上面已经提到,如果调用某个方法的wait()方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态,等待后续再次获得此对象的锁(Thread 类中的sleep方法使得当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁);
notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话,则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。
同样地,调用某个方法的notify()方法,当前线程也必须拥有这个兑现大哥monitor,因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。
Condition是在java 1.5中才出现的,它用来替代传统的Object中的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式事项线程间协作更加安全和高效。因此通常来说比较推荐使用Condition。
condition是个接口,基本方法就是await()和signal()方法;
condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间可以使用Condition中的await()对应Object的wait();Condition中的signal()对应Object的notify();Condition中的signalAll()对应Object的notifyAll()
2. 下面有关java的引用类型,说法正确的有?
-
A 被GCroot强引用=Gcroot对象来说,只要有强引用的存在,它就会一直存在于内存中
-
B 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
-
C 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存
-
D 一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的空间
正确答案:A B C D
题解:
四种引用类型
JDK1.2 之前,一个对象只有"已被引用“和"未被引用"两种状态,这将无法描述某些特殊情况下的对象,比如,当内存充足时需要保留,而内存紧张时才需要被抛弃的一类对象。
所以在JDK1.2 之后,java对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,这4种引用的强度依次减弱。
一,强引用
Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收 obj = null; // 手动置null
只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了
二,软引用
软引用是用来描述一些非必须但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等,在JDK1.2之后,用java.ref.SoftReference类来表示软引用。
三,弱引用
弱引用的引用强度比软引用要更弱一点,无论内存是否足够,只要JVM开始进行垃圾回收,那些被弱引用关联的对象都会被回收。在JDK1.2 之后,用java.lang.ref.WeakReference来表示弱引用。
四,虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么他就和没有任何引用一样,它随时可能被回收,在JDK1.2之后,用PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个get()方法,而且它的get()方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和ReferenceQueue引用队列一起使用。
3. 下列哪个选项是Java调试器?如果编译器返回程序代码的错误,可以用它对程序进行调试。
-
A java
-
B javadoc
-
C jdb
-
D javaprof
参考答案:C
题解:
C java调试器jdb.exe
4. 以下Java程序运行的结果是:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
-
A 1true
-
B 2true
-
C 1false
-
D 2false
正确答案:A
题解:
Java种处理8种基本的数据类型用的都是值传递,其他所有类型都用的是引用传递,由于这8种基本数据类型的包装类型都是不可变类,因此增加了对"按引用传递"的理解难度。其实还是很好理解的,题目中doSomething方法种new了一个对象,这是误导大家选择答案C的原因。其实,按引用传递的实际是将地址值的副本作为实参代替方法中的形参,因此var2与var1里面存储的地址值仍然是一样的,方法种操作的只是var2的一个副本值,并不影响var2本身存储的地址值,所以答案选择A。
5. java语言的下面几种数组复制方法中,哪个效率最高?
-
A for 循环逐一复制
-
B System.arraycopy
-
C Array.copyOf
-
D 使用clone方法
正确答案:B
题解:
复制的效率System.arraycopy>clone>Arrays.copyOf>for循环
在System类源码中给出了arraycopy的方法,是native方法,也就是本地方法,肯定是最快的。而Arrays.copyOf(注意是Arrays类,不是Array)的实现,在源码中是调用System.copyOf的,多了一个步骤,肯定就不是最快的。