深圳恒拓高科信息技术有限公司广州分公司答案_第1页
深圳恒拓高科信息技术有限公司广州分公司答案_第2页
深圳恒拓高科信息技术有限公司广州分公司答案_第3页
深圳恒拓高科信息技术有限公司广州分公司答案_第4页
深圳恒拓高科信息技术有限公司广州分公司答案_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、选择题:1.b2.d 3.ad 4.c5.d6.d 7.BADCE8.b9.D10.11.a12.b13A14C15.b实例化三个线程,一个打印a,一个打印b,一个打印c,三个线程同时执行。要求打印出 6 个连着的 abc一道编程题如下:实例化三个线程,一个线程打印 a,一个线程打印 b,一个线程打印c,三个线程同时执行,要求打印出10 个连着的abc。题目分析:通过题意我们可以得出,本题需要我们使用三个线程,三个线程分别会打印 6 次字符,关键是如何保证顺序一定是 abc.呢。所以此题需要同步机制来解决问题!令打印字符 A 的线程为 ThreadA,打印B 的 ThreadB, 打印C 的为

2、 ThreadC。问题为三线程间的同步唤醒操作,主要的目的就是使程序按 ThreadA-ThreadB-ThreadC-ThreadA 循环执行三个线程,因此本人整理出了三种方式来解决此问题。一、通过两个锁(不推荐,可读性和安全性比较差)package com.demo.test;/* * 基于两个 lock 实现连续打印 abcabc. * author lixiaoxi * */public class TwoLockPrinter implements Runnable / 打印次数 private static final int PRINT_COUNT = 10; / 前一个线程的打

3、印锁 private final Object fontLock; / 本线程的打印锁 private final Object thisLock; / 打印字符 private final char printChar; public TwoLockPrinter(Object fontLock, Object thisLock, char printChar) this.fontLock = fontLock; this.thisLock = thisLock; this.printChar = printChar; Override public void run() / 连续打印 PR

4、INT_COUNT 次 for (int i = 0; i PRINT_COUNT; i+) / 获取前一个线程的打印锁 synchronized (fontLock) / 获取本线程的打印锁 synchronized (thisLock) / 通过本线程的打印锁唤醒后面的线程 / notify 和 notifyall 均可,因为同一时刻只有一个线程在等待thisLock.notify(); / 不是最后一次则通过 fontLock 等待被唤醒 / 必须要加判断,不然虽然能够打印 10 次,但 10 次后就会直接死锁 if(i PRINT_COUNT - 1) try / 通过fontLock

5、 等待被唤醒fontLock.wait(); catch (InterruptedException e) e.printStackTrace();/打印字符System.out.print(printChar); public static void main(String args) throws InterruptedException / 打印 A 线程的锁 Object lockA = new Object(); / 打印 B 线程的锁 Object lockB = new Object(); / 打印 C 线程的锁 Object lockC = new Object(); / 打印

6、 a 的线程 Thread threadA = new Thread(new TwoLockPrinter(lockC, lockA, A); / 打印 b 的线程 Thread threadB = new Thread(new TwoLockPrinter(lockA, lockB, B); / 打印 c 的线程 Thread threadC = new Thread(new TwoLockPrinter(lockB, lockC, C); Thread.sleep(100); threadC.start(); Thread.sleep(100); 打印结果:ABCABCABCABCABCA

7、BCABCABCABCABC分析:此解法为了为了确定唤醒、等待的顺序,每一个线程必须同时持有两个对象锁,才能继续执行。一个对象锁是 fontLock,就是前一个线程所持有的对象锁,还有一个就是自身对象锁 thisLock。主要的思想就是,为了控制执行的顺序,必须要先持有fontLock 锁,也就是前一个线程要释放掉前一个线程自身的对象锁,当前线程再去申请自身对象锁,两者兼备时打印,之后首先调用 thisLock.notify()释放自身对象锁,唤醒下一个等待线程,再调用fontLock.wait()释放 prev 对象锁,暂停当前线程,等待再次被唤醒后进入循环。运行上述代码,可以发现三个线程循

8、环打印 ABC,共 10 次。程序运行的主要过程就是 A 线程最先运行,持有 C,A 对象锁,后释放 A 锁,唤醒 B。线程 B 等待 A 锁,再申请 B 锁,后打印Thread.sleep(100); / 确保按顺序A、B、C 执行threadB.start();/ 依次开启a b c 线程threadA.start();B,再释放 B 锁,唤醒 C,线程 C 等待 B 锁,再申请 C 锁,后打印 C,再释放 C 锁,唤醒A。看起来似乎没什么问题,但如果你仔细想一下,就会发现有问题,就是初始条件,三个线程按照 A,B,C 的顺序来启动,按照前面的思考,A 唤醒 B,B 唤醒 C,C 再唤醒

9、A。但是这种假设依赖于 JVM 中线程调度、执行的顺序,所以需要手动控制他们三个的启动顺序,即 Thread.Sleep(100)。二、通过一个 ReentrantLock 和三个conditon 实现(推荐,安全性,性能和可读性较高)package com.demo.test;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;/* * 基于一个 ReentrantLock 和三个 conditon 实现连续打印 abcabc. * author lixiaox

10、i * */public class RcSyncPrinter implements Runnable / 打印次数 private static final int PRINT_COUNT = 10; / 打印锁 private final ReentrantLock reentrantLock; / 本线程打印所需的 condition private final Condition thisCondtion; / 下一个线程打印所需要的 condition private final Condition nextCondtion; / 打印字符 private final char p

11、rintChar; public RcSyncPrinter(ReentrantLock reentrantLock, Condition thisCondtion, Condition nextCondition, char printChar) this.reentrantLock = reentrantLock; this.nextCondtion = nextCondition; this.thisCondtion = thisCondtion; this.printChar = printChar; Override public void run() try / 连续打印 PRIN

12、T_COUNT 次 for (int i = 0; i PRINT_COUNT; i+) /打印字符System.out.print(printChar);/ 获取打印锁 进入临界区reentrantLock.lock(); / 使用 nextCondition 唤醒下一个线程 / 因为只有一个线程在等待,所以signal 或者signalAll 都可以nextCondtion.signal(); / 不是最后一次则通过 thisCondtion 等待被唤醒 / 必须要加判断,不然虽然能够打印 10 次,但 10 次后就会直接死锁 if (i PRINT_COUNT - 1) try / 本线

13、程让出锁并等待唤醒thisCondtion.await(); catch (InterruptedException e) e.printStackTrace(); finally public static void main(String args) throws InterruptedException / 释放打印锁reentrantLock.unlock(); / 写锁 ReentrantLock lock = new ReentrantLock(); / 打印 a 线程的 condition Condition conditionA = lock.newCondition(); /

14、 打印 b 线程的 condition Condition conditionB = lock.newCondition(); / 打印 c 线程的 condition Condition conditionC = lock.newCondition(); / 实例化 A 线程 Thread printerA = new Thread(new RcSyncPrinter(lock, conditionA, conditionB, A); / 实例化 B 线程 Thread printerB = new Thread(new RcSyncPrinter(lock, conditionB, con

15、ditionC, B); / 实例化 C 线程 Thread printerC = new Thread(new RcSyncPrinter(lock, conditionC, conditionA, C); Thread.sleep(100); printerB.start(); Thread.sleep(100);/ 依次开始A B C 线程printerA.start(); printerC.start(); 打印结果:ABCABCABCABCABCABCABCABCABCABC分析:仔细想想本问题,既然同一时刻只能有一个线程打印字符,那我们为什么不使用一个同步锁 ReentrantLo

16、ck?线程之间的唤醒操作可以通过 Condition 实现,且 Condition 可以有多个,每个 condition.await 阻塞只能通过该condition 的signal/signalall 来唤醒!这是synchronized 关键字所达不到的,那我们就可以给每个打印线程一个自身的 condition和下一个线程的 condition,每次打印字符后,调用下一个线程的 condition.signal 来唤醒下一个线程,然后自身再通过自己的 condition.await 来释放锁并等待唤醒。三、通过一个锁和一个状态变量来实现(推荐)package com.demo.test;/

17、* * 基于一个锁和一个状态变量实现连续打印 abcabc. * author lixiaoxi * */public class StateLockPrinter /状态变量 private volatile int state=0; / 打印线程 private class Printer implements Runnable /打印次数 private static final int PRINT_COUNT=10; /打印锁 private final Object printLock; /打印标志位 和 state 变量相关 private final int printFlag;

18、 /后继线程的线程的打印标志位,state 变量相关 private final int nextPrintFlag; /该线程的打印字符 private final char printChar; public Printer(Object printLock, int printFlag,int nextPrintFlag, char printChar) super(); this.printLock = printLock; this.printFlag=printFlag; this.nextPrintFlag=nextPrintFlag; this.printChar = prin

19、tChar; Override public void run() /获取打印锁 进入临界区 synchronized (printLock) /连续打印 PRINT_COUNT 次 for(int i=0;iPRINT_COUNT;i+) /循环检验标志位 每次都阻塞然后等待唤醒 while (state!=printFlag) try printLock.wait(); catch (InterruptedException e) return; /设置状态变量为下一个线程的标志位 state=nextPrintFlag;/注意要 notifyall,不然会死锁,因为 notify 只一个

20、,/打印字符System.out.print(printChar); /但是同时等待的是两个,如果唤醒的不是正确那个就会没人唤醒, public void test() throws InterruptedException /锁 Object lock=new Object(); /打印 A 的线程 Thread threadA=new Thread(new Printer(lock, 0,1, A); /打印 B 的线程 Thread threadB=new Thread(new Printer(lock, 1,2, B); /打印 C 的线程 Thread threadC=new Thr

21、ead(new Printer(lock, 2,0, C); Thread.sleep(1000); threadB.start(); Thread.sleep(1000);/一次启动A B C 线程threadA.start();死锁了printLock.notifyAll(); threadC.start(); public static void main(String args) throws InterruptedException StateLockPrinter print = new StateLockPrinter(); print.test(); 打印结果:ABCABCAB

22、CABCABCABCABCABCABCABC分析:状态变量是一个 volatile 的整型变量,0 代表打印 a,1 代表打印b,2 代表打印c,三个线程都循环检验标志位,通过阻塞前和阻塞后两次判断可以确保当前打印的正确顺序,随后线程打印字符,然后设置下一个状态字符,唤醒其它线程,然后重新进入循环。JavaScript 原型,原型链 ? 有什么特点?1.JS 中每个函数都存在有一个原型对象属性 prototype。并且所有函数的默认原型都是Object 的实例。2.每个继承父函数的子函数的对象都包含一个内部属性_proto_。该属性包含一个指针,指向父函数的 prototype。若父函数的原型

23、对象的_proto_属性为再上一层函数。在此过程中就形成了原型链。3.原型链实现了继承。原型链存在两个问题:a 包含引用类型值的原型属性会被所有实例共享。b 在创建子类型时,无法向超类型的构造函数中传递参数。写一个例子,并说明什么是闭包,闭包(closure)是 javascript 的一大难点,也是它的特色。很多高级应用都要依靠闭包来实现。1、变量作用域要理解闭包,首先要理解 javascript 的特殊的变量作用域。变量的作用域无非就两种:全局变量和局部变量。javascript 语言的特别之处就在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。注意点:在函数内

24、部声明变量的时候,一定要使用var 命令。如果不用的话,你实际上声明的是一个全局变量!2、如何从外部读取函数内部的局部变量?出于种种原因,我们有时候需要获取到函数内部的局部变量。但是,上面已经说过了,正常情况下,这是办不到的!只有通过变通的方法才能实现。那就是在函数内部,再定义一个函数。function f1() var n=999; function f2() alert(n); / 999 在上面的代码中,函数 f2 就被包括在函数 f1 内部,这时f1 内部的所有局部变量,对f2 都是可见的。但是反过来就不行,f2 内部的局部变量,对 f1 就是不可见的。这就是 Javascript 语

25、言特有的链式作用域结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然 f2 可以读取f1 中的局部变量,那么只要把f2 作为返回值,我们不就可以在f1 外部读取它的内部变量了吗!3、闭包的概念上面代码中的 f2 函数,就是闭包。各种专业文献的闭包定义都非常抽象,我的理解是: 闭包就是能够读取其他函数内部变量的函数。由于在 javascript 中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数“。所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。闭包可以用

26、在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中,不会在 f1 调用后被自动清除。为什么会这样呢?原因就在于 f1 是 f2 的父函数,而 f2 被赋给了一个全局变量,这导致 f2始终在内存中,而 f2 的存在依赖于 f1,因此 f1 也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。这段代码中另一个值得注意的地方,就是nAdd=function()n+=1这一行,首先在 nAdd前面没有使用 var 关键字,因此 nAdd 是一个全局变量,而不是局部变量。其次,nAdd 的值是一个函数(anonymous function),而这个函数本身也是一个闭包,所以nAdd 相当于是一个 setter,可以在函

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论