JAVA面试题

java

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

第一个面试题: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,0);

Node node2=new Node("B",lock,indexs,1);

Node node3= new Node("C",lock,indexs,2);

indexs.put(0,node1);

indexs.put(1,node2);

indexs.put(2,node3);

node1.beforeWork();

node2.beforeWork();

node3.beforeWork();

try{

TimeUnit.SECONDS.sleep(3);

}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()-1){

isLast=true;

}else{

isLast=false;

}

}finally {

readLock.unlock();

}

}

@Override

public void run() {

while (true){

readLock.lock();

if(isRefresh){continue;}

try{

if(this.index==0&&!this.isWorked){

System.out.print(this.message);

this.isWorked=true;

}else if(index!=0){

Node node= maps.get(index-1);

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(1);

}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=0;

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面试题 的全部内容, 来源链接: utcz.com/z/390083.html

回到顶部