main函数是一个线程 t.start开启了另一个线程。这两个线程同时在跑,有时候main的线程快,有时候t的线程快。在t.start();后面加上Thread.sleep(1000); 这样一定是 run.
【Answer】 AF
【例题辨析】 A. 题意:超过两个线程可能立即出现死锁。
符合死锁定义。
B. 题意:Java虚拟机的实现能确保多个线程不会进入死锁状态。
Java语言中解决并发(Concurrent)运行冲突并不是由Java虚拟机负责的,而是由应用程序自行处理,比如同步化(Synchronization)等机制都由程序员在应用设计中使用的,所以,Java虚拟机并不能保证不发生死锁。
C. 题意:只要死锁线程的sleep()方法睡眠时间期满,死锁线程就会获释。
这种观点显然没有正确理解Deadlock与sleep之间的区别,死锁是线程对资源的竞争造成的,线程睡眠期满并不能保证线程获得所需资源。
D. 题意:只有当wait()、notify()、notifyAll()这些方法不正确使用时死锁才发生。
wait()、notify()、notifyAll()这些方法不正确使用时确实可以造成死锁,但不是死锁发生的唯一原因,根本原因还是资源竞争,因此别的因素也可以造成死锁。
E. 题意:只有当同步块不正确使用时单线程应用才会死锁。
死锁是发生在两个或两个以上线程之间,既然是单线程应用那就谈不上死锁了。
F. 题意:如果一个程序片断会死锁,那么你就不能通过插入Thread.yield()方法调用消除死锁。
Thread.yield()方法功能是告诉线程调度者当前线程愿意让出对处理器(CPU)的占用,线程调度者甚至可以不理睬这个方法。造成死锁的资源不仅是处理器,显然这种方式并不足以解决死锁。
(1)线程同步(Thread Synchronization)
线程间通信主要是通过共享字段(Field)或对象引用实现的,这种通信形式虽然高效,但会带来线程干扰(Thread Interference)和内存不一致的弊端,线程同步机制就是防止这类弊端的机制。不过,线程同步机制又会带来线程竞争(Thread Contention)问题,即在两个或两个以上线程同时访问同一资源时导致线程阻塞。
(2)内部锁(Intrinsic Lock),又称监控锁(Monitor Lock)
Java同步化机制是围绕内部锁建立的,每个对象都拥有唯一的一把内部锁,当线程需要排他性地访问某个对象时,这个线程就需要拥有那个对象的内部锁,一旦这个线程拥有那个对象的内部锁,其他线程就不能再获得那把内部锁,如果其他线程仍试图去获取那把内部锁将会被阻塞。
(3)同步化方法(Synchronized Method)和同步化语句(Synchronized Statement)
Java语言为同步化机制提供了两种基本形式,即同步化方法(Synchronized Method)和同步化语句(Synchronized Statement)。synchronized是建立同步化方法或语句的关键词。
当一个线程执行一个同步化方法时,线程就默认拥有同步化方法所在对象的内部锁,其他线程要调用这个对象的同步化方法(即使是不同的同步化方法)时都会被阻塞,直到第一个线程执行完成同步化方法释放内部锁后才能再执行这个对象的同步化方法。
同步化语句则是更加灵活的同步化机制,通过synchronized关键词明确指定提供内部锁的对象,这样同一个对象中不同的同步化语句块就可以拥有不同的内部锁,不同的同步化语句块就可以让不同的线程调用执行。
(4)wait()、notify()、notifyAll()方法
1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。 2,notify():唤醒线程池中一个线程(任意). 3,notifyAll():唤醒线程池中的所有线程。
调用这几个方法的对象的内部锁必须被当前线程获得,如果当前线程不是主调对象内部锁的拥有者,则会抛出IllegalMonitorStateException。
让调用这几个方法的线程拥有主调对象内部锁的方式,主要有: (a)执行主调对象中同步化实例方法; (b)执行主调对象同步化语句块; (c)对于Class对象,执行它的同步化静态方法。
【例题】
void waitForSignal(){ Object obj = new Object(); synchronized (Thread.currentThread()) { obj.wait(); obj.notify(); } }Which statement is true?A. This code can throw anInterruptedException.B. This code can throw anIllegalMonitorStateException.C. This code can throw aTimeoutException after ten minutes.D. Reversing the order ofobj.wait() and obj.notify() might cause this method to complete normally.E. A call to notify() ornotifyAll() from another thread might cause this method to complete normally.F. This code does NOT compileunless "obj.wait()" is replaced with "((Thread)obj).wait()".【Answer】 B
【例题辨析】
(1)wait()和notify()这两个方法都会抛出IllegalMonitorStateException,这个异常是RuntimeException的子类,属于unchecked exception,可以不捕捉。但是,wait()方法还会抛出InterruptedException,这个异常必须捕捉,因此程序有编译错误。应该为waitForSignal方法声明中添加throws InterruptedException: void waitForSignal() throws InterruptedException { ……
或者,为wait()和notify()方法调用语句添加try…catch…
(2)本例中,wait()和notify()方法的主调对象是obj,而obj对象的内部锁没有被当前线程取得,不符合wait()、notify()方法的调用条件,因此调用waitForSignal()时,会抛出如下异常:
Exception in thread "main"java.lang.IllegalMonitorStateExceptionatjava.lang.Object.wait(Native Method) atjava.lang.Object.wait(Unknown Source)atExamA_3.waitForSignal(ExamA_3.java:6)atExamA_3.main(ExamA_3.java:13)解决方案是将synchronized (Thread.currentThread())修改为synchronized (obj),这样当前线程就取得了obj对象的内部锁。
A. InterruptedException在编译时就会发现,因此不会在运行时抛出; B. 根据上面分析可知正确; C. 线程死锁是无法预知时间的; D. 本程序错误不在于obj.wait() and obj.notify()调用顺序,而是在于当前线程没有取得obj内部锁; E. 同上 F. 同上
【例题辨析】 (1)主类Tester实现了线程方法run(),run()的主要工作就是取得当前线程号,main()方法创建了两个Tester类的线程对象,既然有两个线程对象,也就意味着run()代码在内存映像中有两份,即这两个run()方法是各自独立运行在两个不同线程中,因此,Thread.currentThread().getId()取得的是各自的线程号;
(2)线程号取得后作为参数传递给PingPong2类对象pp2的hit()方法,hit()方法负责显示输出信息,hit()是同步化方法,也就意味着当某个线程调用它时,另外的线程必须等待它运行结束,才能取得调用hit()的资格。
A. 从输出信息可以看出,5号线程调用同步化方法hit()时,该方法中循环还未运行结束,6号线程就又调用hit()输出信息,这违背了同步化方法机制;
B. 从输出信息可以看出,6号线程调用同步化方法hit()结束后,5号线程才能调用hit()输出信息,这符合了同步化方法机制;
C. 同A
D. 出现6、5、7三个线程号,显然不符合本题只有2个线程。
【知识点】 (1)Thread类的start()方法 start()方法用于启动线程的执行,也就是让run()方法开始运行。 start()方法只允许执行一次,也就是说一个线程只允许启动一次,即使执行完毕也不允许重新启动,否则会抛出IllegalThreadStateException。
public class Threads4 { public static void main (String[] args) { new Threads4().go();}public void go() { Runnable r = new Runnable() { public void run() { System.out.print("foo"); } }; Thread t = new Thread(r); t.start(); t.start(); }}What is the result?A. Compilation fails.B. An exception is thrown at runtime.C. The code executes normally and prints "foo".D. The code executes normally, but nothing is printed.Explanation/Reference:Exception in thread "main" java.lang.IllegalThreadStateExceptionat java.lang.Thread.start(Unknown Source)at Threads4.go(Threads4.java:14)at Threads4.main(Threads4.java:3)foo【答案】B
A. 可以在Eclipse开发环境中尝试录入本程序 ,如果编辑窗口中没有错误提示出现,通常不存在编译错误;
B. 同样,在Eclipse开发环境中尝试录入本程序,可以看到如下信息:
fooException in thread “main”Java.lang.IllegalThreadStateException
atjava.lang.Thread.start(Unknown Source) atThreads4.go(Threads4.java:17) atThreads4.main(Threads4.java:5)上述信息说明运行时抛出了异常,这是因为Thread类的start()方法只允许执行一次,也就是说一个线程只允许启动一次,即使执行完毕也不允许重新启动;
Answer: BE
新闻热点
疑难解答