黑马程序员---空中网面试题

2024-09-07 16:18

本文主要是介绍黑马程序员---空中网面试题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

空中网4k/5k月薪挑选大四实习生的线程题
    两年前,我们一个大四的学员去应聘空中网的实习生职位,空中网只给他出了三道线程题,拿回家做两天后再去给经理讲解,如果前两题做好了给4k月薪,第三道题也做出来的话就给5k的月薪。这样的实习薪水和招聘要求,不需要有工作经验的限制,纯粹是技术功底的比拼和考核,而不像许多其他公司非要招两年工作经验的人,逼得那些刚毕业和未毕业的大学生不得不去撒谎,不得不去做假简历,甚至假毕业证!所以,空中网的这份工作对未毕业的大学生来说,还是很有吸引力的。

第一题

现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,程序只需要运行4秒即可打印完这些日志对象。原始代码如下:

package read;public class Test {public static void main(String[] args){//打印一行现在的时间,多少秒:System.out.println("begin:"+(System.currentTimeMillis()/1000));for(int i=0;i<16;i++){  //这行代码不能改动final String log = ""+(i+1);//这行代码不能改动{Test.parseLog(log);}}}//parseLog方法内部的代码不能改动public static void parseLog(String log){//打印log序号+现在的时间(秒)System.out.println(log+":"+(System.currentTimeMillis()/1000));try {//休息一秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}		}
}
运行结果:

begin:1400554274

1:1400554274

2:1400554275

3:1400554276

4:1400554277

5:1400554278

6:1400554279

7:1400554280

8:1400554281

9:1400554282

10:1400554283

11:1400554284

12:1400554285

13:1400554286

14:1400554287

15:1400554288

16:1400554289


修改之后

package read;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Test {public static void main(String[] args){//打印一行现在的时间,多少秒:System.out.println("begin:"+(System.currentTimeMillis()/1000));final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16);for(int i=0;i<16;i++){  //这行代码不能改动final String log = ""+(i+1);//这行代码不能改动{//Test.parseLog(log);try {queue.put(log);} catch (InterruptedException e) {e.printStackTrace();}}}for(int i=0;i<4;i++){new Thread(new Runnable(){public void run() {try {for(int j=0;j<4;j++){Test.parseLog(queue.take());}} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}//parseLog方法内部的代码不能改动public static void parseLog(String log){//打印log序号+现在的时间(秒)System.out.println(log+":"+(System.currentTimeMillis()/1000));try {//休息一秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}		}
}
运行结果:

begin:1400592551

1:1400592551

2:1400592551

3:1400592551

4:1400592551

5:1400592552

6:1400592552

7:1400592552

8:1400592552

9:1400592553

10:1400592553

11:1400592553

12:1400592553

13:1400592554

15:1400592554

14:1400592554

16:1400592554


这样定义一个空间的阻塞队列数组也是可以的:
package read;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Test {public static void main(String[] args){//打印一行现在的时间,多少秒:System.out.println("begin:"+(System.currentTimeMillis()/1000));final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);for(int i=0;i<4;i++){new Thread(new Runnable(){public void run() {try {while(true){Test.parseLog(queue.take());}} catch (InterruptedException e) {e.printStackTrace();}}}).start();}for(int i=0;i<16;i++){  //这行代码不能改动final String log = ""+(i+1);//这行代码不能改动{//Test.parseLog(log);try {queue.put(log);} catch (InterruptedException e) {e.printStackTrace();}}}}//parseLog方法内部的代码不能改动public static void parseLog(String log){//打印log序号+现在的时间(秒)System.out.println(log+":"+(System.currentTimeMillis()/1000));try {//休息一秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}		}
}
运行结果:

begin:1400594575

1:1400594575

2:1400594575

3:1400594575

4:1400594575

5:1400594576

6:1400594576

7:1400594576

8:1400594576

9:1400594577

10:1400594577

11:1400594577

12:1400594577

13:1400594578

14:1400594578

15:1400594578

16:1400594578


*第二题

现成程序中的Test类中的代码在不断地产生数据,然后交给TestDo.doSome()方法去处理,就好像生产者在不断地产生数据,消费者在不断消费数据。请将程序改造成有10个线程来消费生成者产生的数据,这些消费者都调用TestDo.doSome()方法去进行处理,故每个消费者都需要一秒才能处理完,程序应保证这些消费者线程依次有序地消费数据,只有上一个消费者消费完后,下一个消费者才能消费数据,下一个消费者是谁都可以,但要保证这些消费者线程拿到的数据是有顺序的。原始代码如下:
package queue;public class Test {public static void main(String[] args) {System.out.println("begin:"+(System.currentTimeMillis()/1000));for(int i=0;i<10;i++){  //这行不能改动String input = i+"";  //这行不能改动String output = TestDo.doSome(input);System.out.println(Thread.currentThread().getName()+ ":" + output);}}
}//不能改动此TestDo类
class TestDo {public static String doSome(String input){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}String output = input + ":"+ (System.currentTimeMillis() / 1000);return output;}
}

修改后的代码

package queue;import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;public class Test {public static void main(String[] args) {System.out.println("begin:"+(System.currentTimeMillis()/1000));//定义一盏灯。相当于Lock。final Semaphore semaphore = new Semaphore(1);//一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作。final SynchronousQueue<String> queue = new SynchronousQueue<String>();for(int i=0;i<10;i++){new Thread(new Runnable(){public void run() {try {semaphore.acquire();String input = queue.take();String output = TestDo.doSome(input);System.out.println(Thread.currentThread().getName()+ ":" + output);} catch (InterruptedException e) {e.printStackTrace();}finally{semaphore.release();}}}).start();}for(int i=0;i<10;i++){  //这行不能改动String input = i+"";  //这行不能改动try {queue.put(input);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}//不能改动此TestDo类
class TestDo {public static String doSome(String input){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}String output = input + ":"+ (System.currentTimeMillis() / 1000);return output;}
}
运行结果:

begin:1400596420

Thread-0:0:1400596421

Thread-1:1:1400596422

Thread-2:2:1400596423

Thread-3:3:1400596424

Thread-4:4:1400596425

Thread-5:5:1400596426

Thread-6:6:1400596427

Thread-7:7:1400596428

Thread-8:8:1400596429

Thread-9:9:1400596430


第三题

现有程序同时启动了4个线程去调用TestDo.doSome(key, value)方法,由于TestDo.doSome(key, value)方法内的代码是先暂停1秒,然后再输出以秒为单位的当前时间值,所以,会打印出4个相同的时间值,如下所示:
4:4:1258199615
1:1:1258199615
3:3:1258199615
1:2:1258199615
        请修改代码,如果有几个线程调用TestDo.doSome(key, value)方法时,传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果,即当有两个线程的key都是"1"时,它们中的一个要比另外其他线程晚1秒输出结果,如下所示:
4:4:1258199615
1:1:1258199615
3:3:1258199615
1:2:1258199616
 总之,当每个线程中指定的key相等时,这些相等key的线程应每隔一秒依次输出时间值(要用互斥),如果key不同,则并行执行(相互之间不互斥)。原始代码如下:
package syn;//不能改动此Test类	public class Test extends Thread{private TestDo testDo;private String key;private String value;public Test(String key,String key2,String value){this.testDo = TestDo.getInstance();/*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/this.key = key+key2; this.value = value;}public static void main(String[] args) throws InterruptedException{Test a = new Test("1","","1");Test b = new Test("1","","2");Test c = new Test("3","","3");Test d = new Test("4","","4");System.out.println("begin:"+(System.currentTimeMillis()/1000));a.start();b.start();c.start();d.start();}public void run(){testDo.doSome(key, value);}}class TestDo {private TestDo() {}private static TestDo _instance = new TestDo();	public static TestDo getInstance() {return _instance;}public void doSome(Object key, String value) {// 以大括号内的是需要局部同步的代码,不能改动!{try {Thread.sleep(1000);System.out.println(key+":"+value + ":"+ (System.currentTimeMillis() / 1000));} catch (InterruptedException e) {e.printStackTrace();}}}}
运行结果:

begin:1400601982

1:1:1400601983

4:4:1400601983

1:2:1400601983

3:3:1400601983


修改之后

package syn;import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;//不能改动此Test类	
public class Test extends Thread{private TestDo testDo;private String key;private String value;public Test(String key,String key2,String value){this.testDo = TestDo.getInstance();/*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*///它是两个变量相加的结果,在运行时候才能知道结果,所以编译器无法把两个"1"识别成为一个对象。this.key = key+key2; /*如果是这样写,编译器就会把它们看作是一个对象:* String a = "1"+"";* String b = "1"+"";*/this.value = value;}public static void main(String[] args) throws InterruptedException{Test a = new Test("1","","1");Test b = new Test("1","","2");Test c = new Test("3","","3");Test d = new Test("4","","4");System.out.println("begin:"+(System.currentTimeMillis()/1000));a.start();b.start();c.start();d.start();}public void run(){testDo.doSome(key, value);}
}class TestDo {//单例设计模式private TestDo() {}private static TestDo _instance = new TestDo();	public static TestDo getInstance() {return _instance;}//new一个支持多线程并发操作的ArrayList,来存放那些key。CopyOnWriteArrayList<Object> keys = new CopyOnWriteArrayList<Object>();public void doSome(Object key, String value) {Object obj = key;//如果集合里没有这个key,就添加到集合里。如果集合里有这个key,就把这个新的对象替换成集合里哪个旧的。if(!keys.contains(key)){keys.add(key);}else{for(Iterator<Object> it=keys.iterator(); it.hasNext();){Object o = it.next();if(o.equals(obj)){obj = o;}}}synchronized(obj)// 以大括号内的是需要局部同步的代码,不能改动!{try {Thread.sleep(1000);System.out.println(key+":"+value + ":"+ (System.currentTimeMillis() / 1000));} catch (InterruptedException e) {e.printStackTrace();}}}
}
//这样相同的key值就不会在同一秒打印了。
//但是排除另外一种极罕见的可能,就是毫秒换算秒的误差。
运行结果:

begin:1400601770

4:4:1400601771

3:3:1400601771

1:1:1400601771

1:2:1400601772



这篇关于黑马程序员---空中网面试题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145542

相关文章

荣耀嵌入式面试题及参考答案

在项目中是否有使用过实时操作系统? 在我参与的项目中,有使用过实时操作系统。实时操作系统(RTOS)在对时间要求严格的应用场景中具有重要作用。我曾参与的一个工业自动化控制项目就采用了实时操作系统。在这个项目中,需要对多个传感器的数据进行实时采集和处理,并根据采集到的数据及时控制执行机构的动作。实时操作系统能够提供确定性的响应时间,确保关键任务在规定的时间内完成。 使用实时操作系统的

一些其他面试题

阿里二面:那你来说说定时任务?单机、分布式、调度框架下的定时任务实现是怎么完成的?懵了。。_哔哩哔哩_bilibili 1.定时算法 累加,第二层每一个格子是第一层的总时间400 ms= 20 * 20ms 2.MQ消息丢失 阿里二面:高并发场景下引进消息队列有什么问题?如何保证消息只被消费一次?真是捏了一把汗。。_哔哩哔哩_bilibili 发送消息失败

zookeeper相关面试题

zk的数据同步原理?zk的集群会出现脑裂的问题吗?zk的watch机制实现原理?zk是如何保证一致性的?zk的快速选举leader原理?zk的典型应用场景zk中一个客户端修改了数据之后,其他客户端能够马上获取到最新的数据吗?zk对事物的支持? 1. zk的数据同步原理? zk的数据同步过程中,通过以下三个参数来选择对应的数据同步方式 peerLastZxid:Learner服务器(Follo

java常用面试题-基础知识分享

什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法相对简单,易于学习和使用。面向对象:Java是一种完全面向对象的语言,支持封装、继承和多态。跨平台性:Java的程序可以在不同的操作系统上运行,称为"Write once,

【Kubernetes】常见面试题汇总(三)

目录 9.简述 Kubernetes 的缺点或当前的不足之处? 10.简述 Kubernetes 相关基础概念? 9.简述 Kubernetes 的缺点或当前的不足之处? Kubernetes 当前存在的缺点(不足)如下: ① 安装过程和配置相对困难复杂; ② 管理服务相对繁琐; ③ 运行和编译需要很多时间; ④ 它比其他替代品更昂贵; ⑤ 对于简单的应用程序来说,可能不

【附答案】C/C++ 最常见50道面试题

文章目录 面试题 1:深入探讨变量的声明与定义的区别面试题 2:编写比较“零值”的`if`语句面试题 3:深入理解`sizeof`与`strlen`的差异面试题 4:解析C与C++中`static`关键字的不同用途面试题 5:比较C语言的`malloc`与C++的`new`面试题 6:实现一个“标准”的`MIN`宏面试题 7:指针是否可以是`volatile`面试题 8:探讨`a`和`&a`

Laravel 面试题

PHP模块 PHP7 和 PHP5 的区别,具体多了哪些新特性? 性能提升了两倍 结合比较运算符 (<=>) 标量类型声明 返回类型声明 try…catch 增加多条件判断,更多 Error 错误可以进行异常处理 匿名类,现在支持通过new class 来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义 …… 了解更多查看文章底部链接 PHP7 新特性 为什么 PHP

【吊打面试官系列-Redis面试题】说说 Redis 哈希槽的概念?

大家好,我是锋哥。今天分享关于 【说说 Redis 哈希槽的概念?】面试题,希望对大家有帮助; 说说 Redis 哈希槽的概念? Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽, 集群的每个节点负责一部分 hash 槽。

【Kubernetes】常见面试题汇总(一)

目录 1.简述 etcd 及其特点? 2.简述 etcd 适应的场景? 3.简述什么是Kubernetes? 4.简述 Kubernetes和 Docker的关系? 1.简述 etcd 及其特点? (1)etcd 是Core0s 团队发起的开源项目,是一个管理配置信息和服务发现(service discovery)的项目,它的目标是构建一个高可用的分布式键值(keyvalue)数据

LabVIEW程序员是怎样成长为大佬

成为一名LabVIEW编程领域的“大佬”需要时间、实践、学习和解决复杂问题的经验。尽管LabVIEW作为一种图形化编程语言在初期可能相对容易上手,但要真正成为精通者,需要在多个层面上深入理解。以下是LabVIEW程序员如何逐步成长为“大佬”的路径: 1. 打好基础 LabVIEW的大佬们通常在初期会打下非常坚实的基础,理解LabVIEW编程的核心概念,包括: 数据流编程模型:Lab