在这里我将收录我面试过程中遇到的一些好玩的面试题目

第一个面试题:ABC问题,有三个线程,工作的内容分别是打印出“A”“B”“C”,需要做的就是让他们顺序的输出ABC  例如:ABCABCABCABC

思路一:我觉得这个功能是需要封装的,而且能够做到,无论多少个线程都能够顺序打印出来,并且基本上不需要改任何代码。我的思路是首先封装一个工作的单元为Node,主要的工作就是打印和竞争锁并且记录加入工作的索引,然后还有一个ConcurrentHashMap储存工作状态。如果全部工作完了之后,由最后一个工作单元刷新状态。下面是实现的代码:

package com.hotusm.concurrent.test;

import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by luqibao on 2016/12/30.
*/
public class ABCSample { private static ReentrantLock lock=new ReentrantLock(); private static volatile TreeMap<Integer,Node> indexs=new TreeMap<>(); public static void main(String[] args){
ReentrantLock lock=new ReentrantLock();
TreeMap<Integer,Node> indexs=new TreeMap<>();
Node node1=new Node("A",lock,indexs,);
Node node2=new Node("B",lock,indexs,);
Node node3= new Node("C",lock,indexs,);
indexs.put(,node1);
indexs.put(,node2);
indexs.put(,node3); node1.beforeWork();
node2.beforeWork();
node3.beforeWork(); try{
TimeUnit.SECONDS.sleep();
}catch (Exception e){ e.printStackTrace();
} node1.start();
node2.start();
node3.start(); synchronized (ABCSample.class){ try{
ABCSample.class.wait();
}catch (Exception e){
e.printStackTrace();
} } } private static class WorkQueue{ private Node tail;
private Node head;
} private static class Node extends Thread{ private static volatile boolean isRefresh=false; private volatile Map<Integer,Node> maps;
private volatile boolean isWorked=false;
private final int index; //索引 private String message;
private volatile Lock readLock;
private boolean isLast=false; public Node(String message,Lock lock,Map<Integer,Node> maps,int index){
this.message=message;
this.readLock=lock;
this.maps=maps;
this.index=index;
} public int getIndex() {
return index;
} public void beforeWork(){ readLock.lock();
try{
if(index==maps.size()-){
isLast=true;
}else{
isLast=false;
}
}finally {
readLock.unlock();
} }
@Override
public void run() {
while (true){
readLock.lock();
if(isRefresh){continue;}
try{
if(this.index==&&!this.isWorked){
System.out.print(this.message);
this.isWorked=true;
}else if(index!=){
Node node= maps.get(index-);
if(!node.isWorked){
System.out.print(node.message);
node.isWorked=true;
}else{
if(!this.isWorked){
System.out.print(this.message);
this.isWorked=true;
}else if(this.isWorked&&this.isLast){
refresh();
}
}
}
}catch (Exception e){
Thread.currentThread().interrupt();
e.printStackTrace();
}finally {
readLock.unlock();
} try{
TimeUnit.SECONDS.sleep();
}catch (Exception e){
e.printStackTrace();
} }
} private void refresh(){
isRefresh=true;
for(Map.Entry<Integer,Node> map:maps.entrySet()){
map.getValue().isWorked=false;
}
isRefresh=false;
}
}
}

其实上面还有很多封装的地方,注册可以封装成方法,前置工作也是,可以用一个volatile修饰的boolean来标记,同理启动也是一样的,如果能够的话,最好能做到,使用的时候只需要调用一个register(msg) 和start()就可以了

思路二:因为这是一个环形链接结构,所以我们可以通知将锁从head开始一直往后让其他获取一遍,下面代码:

package com.hotusm.concurrent.test;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch; /**
* Created by luqibao on 2017/1/3.
*/
public class ABCSample2 { public static void main(String[] args){ WorkQueue queue= new WorkQueue();
queue.addWork("A");
queue.addWork("B");
queue.addWork("C");
queue.addWork("D");
queue.addWork("E"); queue.startWork(); synchronized (ABCSample2.class){ try{
ABCSample2.class.wait();
}catch (Exception e){
e.printStackTrace();
} }
}
private static class WorkQueue{ private Node head;
private Node tail;
private int num=; private static final Unsafe unsafe = getUnsafe();
private static final long tailOffset;
private static final long headOffset; static {
try {
// 获取当前字段的内存位置 后来替换的地方需要使用
headOffset = unsafe.objectFieldOffset
(WorkQueue.class.getDeclaredField("head"));
tailOffset = unsafe.objectFieldOffset
(WorkQueue.class.getDeclaredField("tail"));
} catch (Exception ex) { throw new Error(ex); }
} private static Unsafe getUnsafe() {
try { Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
singleoneInstanceField.setAccessible(true);
return (Unsafe) singleoneInstanceField.get(null); } catch (Exception e) {
throw new RuntimeException(e);
}
} protected void push(Node node){ for (;;) {
Node t = tail;
if (t == null) {
if (compareAndSetHead(node))
num++;
tail = head;
break;
} else {
if (compareAndSetTail(t, node)) {
num++;
t.next = node;
break;
}
}
}
} /**
*加入工作的顺序就是打印的顺序
* @param message 打印的信息
*/
public void addWork(String message){
Node node=new Node(message);
push(node);
} /**
* 开始进行工作
*/
public void startWork(){
Node.head=this.head;
Node.tail=tail;
Node.latch=new CountDownLatch(num);
Node.currentWork=head; for (Node node=head;node!=null;node=node.next){
node.start();
Node.latch.countDown();
}
} public boolean compareAndSetTail(Node expect,Node newValue){
return unsafe.compareAndSwapObject(this,tailOffset,expect,newValue);
}
public boolean compareAndSetHead(Node expect){
return unsafe.compareAndSwapObject(this,headOffset,null,expect);
} } private static class Node extends Thread{ private static volatile Node currentWork; private static volatile Node head;
private static volatile Node tail;
private static volatile CountDownLatch latch; private String message;
private Node next; public Node(String message) {
this.message = message;
} @Override
public void run() { try {
latch.await();
}catch (Exception e){
e.printStackTrace();
}
for(;;){
if(currentWork==this){
if(!"".equals(message)){
System.out.print(message);
}
if(this==tail){
currentWork=head;
}else{
currentWork=this.next;
}
}
} }
}
}

总的来说,我还是比较喜欢后面这种的,但是还是需要优化,比如在启动之后就不能够添加工作了,验证工作不能重复等等。

第二个面试题:

具体题目如下,

-         Java开发

-         功能要求:

o   网络爬虫,可以使用少量的3方库,但是最好能够用自己写的代码

o   加分点:使用多线程,注意同步和锁

o   将豆瓣(book.douban.com)里的关于“互联网,编程,算法”方面的书籍数据抓下来,并且显示评分最高的前100本数据(要求评价人数超过2000,不足2000的就提取前100)

o   代码和爬下的结果(excel文件)一并放在github里,链接发给你们,再转给我。

这个面试题是一家500强的外企的题目,因为之前一直没有接触过爬虫方面,所以觉得比较有意思,代码在我们的github上面:https://github.com/Housum/crawl.git。

因为当时时间比较紧(白天在项目),本来是想自己写网络和解析的,但是没时间,所以用的都是第三方的,反而觉得除了锁,其他的都是第三方框架的东西。面试官评价还行。

JAVA面试题的更多相关文章

  1. java面试题及答案(转载)

    JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时 ...

  2. 115个Java面试题和答案——终极列表(下)

    第一篇讨论了面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,本章主要讨论异常处理,Java小应用程序,Swing,JDBC,远程方法调用(RMI),Servle ...

  3. Java面试题(全)

    JAVA部分 什么是反射机制?反射机制应用(Struts中反射机制的应用) 答:运行状态中,对于任意一个类,都可以知道它的所有属性和方法,对于任意一个对象都可以调用它的任意一个方法,这种动态获取信息以 ...

  4. Java面试题大全(四)

    JAVA代码查错 1. abstract class Name { private String name; public abstract boolean isStupidName(String n ...

  5. 大公司的Java面试题集

    找工作要面试,有面试就有对付面试的办法.以下一些题目来自我和我朋友痛苦的面试经历,提这些问题的公司包括IBM, E*Trade, Siebel, Motorola, SUN, 以及其它大小公司. 面试 ...

  6. 收集了50道基础的java面试题

    下面的内容是对网上原有的Java面试题集及答案进行了全面修订之后给出的负责任的题目和答案,原来的题目中有很多重复题目和无价值的题目,还有不少的参考答案也是错误的,修改后的Java面试题集参照了JDK最 ...

  7. Java笔试题解答和部分面试题

    面试类  银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...

  8. 转:Java面试题集(51-70) http://blog.csdn.net/jackfrued/article/details/17403101

    Java面试题集(51-70) Java程序员面试题集(51-70) http://blog.csdn.net/jackfrued/article/details/17403101 摘要:这一部分主要 ...

  9. JAVA面试题集之基础知识

                           JAVA面试题集之基础知识 基础知识:  1.C 或Java中的异常处理机制的简单原理和应用. 当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就 ...

  10. [原]Java面试题-将字符串中数字提取出来排序后输出

    [Title][原]Java面试题-将字符串中数字提取出来排序后输出 [Date]2013-09-15 [Abstract]很简单的面试题,要求现场在纸上写出来. [Keywords]面试.Java. ...

随机推荐

  1. 【造轮子】打造一个简单的万能Excel读写工具

    大家工作或者平时是不是经常遇到要读写一些简单格式的Excel? shit!~很蛋疼,因为之前吹牛,就搞了个这东西,还算是挺实用,和大家分享下. 厌烦了每次搞简单类型的Excel读写?不怕~来,喜欢流式 ...

  2. ABP文档 - Javascript Api - Message

    本节内容: 显示信息 确认 Message API给用户显示一个信息,或从用户那里获取一个确认信息. Message API默认使用sweetalert实现,为使sweetalert正常工作,你应该包 ...

  3. ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式

    由于ASP.NET Core应用是一个同时处理多个请求的服务器应用,所以在处理某个请求过程中抛出的异常并不会导致整个应用的终止.出于安全方面的考量,为了避免敏感信息的外泄,客户端在默认的情况下并不会得 ...

  4. lua 学习笔记(1)

    一.lua函数赋值与函数调用         在lua中函数名也是作为一种变量出现的,即函数和所有其他值一样都是匿名的,当要使用某个函数时,需要将该函数赋值给一个变量,这样在函数块的其他地方就可以通过 ...

  5. 为IEnumerable<T>添加RemoveAll<IEnumerable<T>>扩展方法--高性能篇

    最近写代码,遇到一个问题,微软基于List<T>自带的方法是public bool Remove(T item);,可是有时候我们可能会用到诸如RemoveAll<IEnumerab ...

  6. CGI与FastCGI nginx+PHP-FPM

    本文转载自CGI与FastCGI 1.当我们在谈到cgi的时候,我们在讨论什么 最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html. ...

  7. Java定时任务的常用实现

    Java的定时任务有以下几种常用的实现方式: 1)Timer 2)ScheduledThreadPoolExecutor 3)Spring中集成Cron Quartz 接下来依次介绍这几类具体实现的方 ...

  8. Visual Studio Code——Angular2 Hello World 之 2.0

    最近看到一篇用Visual Studio Code开发Angular2的文章,也是一篇入门教程,地址为:使用Visual Studio Code開發Angular 2專案.这里按部就班的做了一遍,感觉 ...

  9. IT雇员及外包商选择:人品第一

    最近,苹果iOS操作系统和智能手机爆出了一个奇葩故障,在播放特定一段五秒钟的视频时能导致手机死机.唯一的解决办法是按住电源键和Home按键进行手机的重启. 第十八届中国国际高新技术成果交易会在深圳举办 ...

  10. 参数探测(Parameter Sniffing)影响存储过程执行效率解决方案

    如果SQL query中有参数,SQL Server 会创建一个参数嗅探进程以提高执行性能.该计划通常是最好的并被保存以重复利用.只是偶尔,不会选择最优的执行计划而影响执行效率. SQL Server ...