楼主,第一道题我没看懂要求。
第二道题,我大概明白你的意思了,不过说实话,这两道面试题的难度真不是盖的。
第二题我大概做了一些,感觉挺有意思的,但也确实有一些难度,我自己也没有觉得很有把握。
上代码package com.test;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;/**
 * Created with IntelliJ IDEA.
 * User: 菜鸟大明
 * Date: 14-8-5
 * Time: 下午9:24
 * To change this template use File | Settings | File Templates.
 */interface WorkItemExecutor
{
    void executeWorkItem(WorkItem w, int parallelism);
}interface WorkItemCompletionCallback
{
    void complete();
}interface WorkItem
{
    void execute(WorkItemCompletionCallback callback);
}public class MyWorkItemExecutor implements WorkItemExecutor{    // 通过我们自己写的ExceptionThreadFactory线程工厂,构造线程池
    static final ExecutorService executorService = Executors.newCachedThreadPool(new ExceptionThreadFactory());    @Override
    public void executeWorkItem(WorkItem w, int parallelism) {        try {
            System.out.println("执行线程");
            for (int i=0;i<10;i++) {
                executorService.execute(new MyThread(i));
            }        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("捕捉异常");
        }
    }    public void addThread(int i) {
        // 通过我们自己写的ExceptionThreadFactory线程工厂,构造线程池
        executorService.execute(new MyThread(i));
    }
}/**
 * 测试类
 */
class Test{
    public static void main(String[] args) {
        MyWorkItemExecutor myWorkItemExecutor = new MyWorkItemExecutor();
        myWorkItemExecutor.executeWorkItem(new MyThread(),10);
    }
}/**
 * 运行线程
 */
class MyThread implements Runnable,WorkItem{
    MyThread(){};
    int i;
    MyThread(int i) {
        this.i = i;
    }    @Override
    public void run() {
        execute(new MyCallBack(i));
    }    @Override
    public void execute(WorkItemCompletionCallback callback) {
        System.out.println("线程" + i + "在执行");
        callback.complete();
    }
}class MyCallBack implements WorkItemCompletionCallback{
    int i;
    MyCallBack(){};
    MyCallBack(int i) {
        this.i = i;
    }    @Override
    public void complete() {
        // 进程结束后,新开启一个进程。
        new MyWorkItemExecutor().addThread(i);
    }
}/**
 * 定义异常线程内容
 */
class MyExceptionThread implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        // 遇到异常,结束前,再开启一个进程。
        t.start();
    }
}/**
 * 定义异常线程工厂
 */
class ExceptionThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        // 此处是捕捉异常的设置。
        thread.setUncaughtExceptionHandler(new MyExceptionThread());
        return thread;
    }
}

解决方案 »

  1.   

    sorry,有个地方写错了
    第40行的  for (int i=0;i<10;i++) {
    应该换成 for (int parallelism=0;parallelism<10;i++) {
      

  2.   

    就是缓存和线程池缓存可以看看OSCache实现,线程池可以直接看jdk里的实现
      

  3.   

    再补充下这两道题的要求:
    The following items should be completed in Java 1.7 without relying on other frameworks. The code should be production ready. Make reasonable assumptions if any information is missing. 
    If needed, make notes explaining the assumptions. Ideally your code can be compiled with Maven.在Java 1.7的环境下开发,不用任何其他的框架或者库
    如果觉得题目里面有缺失的假设,可以自己做合理的假设,并作出自己的解释
      

  4.   

    第一个可以参考redis的实现;第二个别用runnable,用callable,有返回值的,根据返回值或异常去控制。
      

  5.   

    -缓存内的对象存活时间很短,大约10秒左右                      逐出策略
    -系统有非常多的内存(足够用)                                          虽然足够也不能浪费,考虑用个hash算法处理key
    -缓存内存放对象的key是广泛分布于整个keyspace的       存放的key是可配置的?可以有多个缓存
    -每个对象在生命周期里有可能被访问也可能不被访问       ?没看懂
    -每个对象可能被访问多次                                                       没看懂
      

  6.   


    -_-#没让你用框架,是让你去看实现,原理上都是一样的,只是各自API啊框架结构设计思路不大一样而已。-缓存内的对象存活时间很短,大约10秒左右    异步失效(或者其他失效策略,重点保证数据安全)
    -系统有非常多的内存(足够用)
    -缓存内存放对象的key是广泛分布于整个keyspace的    (hash算法保证分布性)
    -每个对象在生命周期里有可能被访问也可能不被访问     (临时失效标识?)
    -每个对象可能被访问多次  线程池那个真没什么好说的,完全就是jdk里的复刻版
      

  7.   


    1. 能解释下逐出策略吗?
    2. 这点用hash算法,我觉得基本大家都没有异议啊
    3。 如果有多个缓存的话之间还有同步问题,这个就相当于一个分布式数据库系统了,会很复杂啊,类似Cassandra这样的
    4. 最后两点说的就是缓存的内容可能被访问一次多次,也可能一次都没有被访问到这个内容就过期啦
      

  8.   


    谢谢你的代码,我看看for (int parallelism=0;parallelism<10;i++) 
    这行有问题吧,parallelism是入参,这里再声明不就重复了吗?还有为什么使用Executors.newCachedThreadPool方法而不是Executors.newFixedThreadPool方法呢?
      

  9.   


    -_-#没让你用框架,是让你去看实现,原理上都是一样的,只是各自API啊框架结构设计思路不大一样而已。-缓存内的对象存活时间很短,大约10秒左右    异步失效(或者其他失效策略,重点保证数据安全)
    -系统有非常多的内存(足够用)
    -缓存内存放对象的key是广泛分布于整个keyspace的    (hash算法保证分布性)
    -每个对象在生命周期里有可能被访问也可能不被访问     (临时失效标识?)
    -每个对象可能被访问多次  线程池那个真没什么好说的,完全就是jdk里的复刻版1 异步失效的话,会不会有数据正确性的隐患呢?如果在失效操作过程中缓存再被读出来,是不是这个时候可能不正确呢?
    2. 线程池那个我觉得直接用jdk里提供的线程池就可以了,你觉得呢? 不知道题目想考我什么呢?会不会用jdk的线程池?
      

  10.   


    -_-#没让你用框架,是让你去看实现,原理上都是一样的,只是各自API啊框架结构设计思路不大一样而已。-缓存内的对象存活时间很短,大约10秒左右    异步失效(或者其他失效策略,重点保证数据安全)
    -系统有非常多的内存(足够用)
    -缓存内存放对象的key是广泛分布于整个keyspace的    (hash算法保证分布性)
    -每个对象在生命周期里有可能被访问也可能不被访问     (临时失效标识?)
    -每个对象可能被访问多次  线程池那个真没什么好说的,完全就是jdk里的复刻版1 异步失效的话,会不会有数据正确性的隐患呢?如果在失效操作过程中缓存再被读出来,是不是这个时候可能不正确呢?
    2. 线程池那个我觉得直接用jdk里提供的线程池就可以了,你觉得呢? 不知道题目想考我什么呢?会不会用jdk的线程池?
    1、 失效失败有自己的处理策略,不管同步异步都有可能会失败。
           失败可以重试,可以报警,等等,这个看失效策略了,反映在实现上可以是可配置的策略(不过内存操作一般都不会失败的,又不是依赖数据库什么的)
           失效的时候被读了,这个就是读不可重复数据了,数据库也有类似的问题,可以配置策略加锁什么的来解决这个问题。一般都不解决这种问题,我们用数据库的时候也是默认容忍这种情况的。
    2、 大概就是考察你的设计思路吧,虽然原理类似,但是设计想法不一样的。譬如你的扩展性好不好,易用性怎么样,容错能力怎么样,维护起来简单不简单
      

  11.   


    谢谢你的代码,我看看for (int parallelism=0;parallelism<10;i++) 
    这行有问题吧,parallelism是入参,这里再声明不就重复了吗?还有为什么使用Executors.newCachedThreadPool方法而不是Executors.newFixedThreadPool方法呢?
    sorry,各种笔误
    应该是这样: for (int i=0;i<parallelism;i++) 理解意思~理解意思。缓存那个,我的理解不应该依赖第三方API应用吧,redis ehCache等都不应该是此次面试题的目的。
    这两道题应该考的是你对JDK自身API的理解,个人认为哈。
    缓存那个,今儿下班前,我要是有时间,我再写一段。
      

  12.   

    package com.wanju.project001.zonghe.test;import java.util.HashMap;public class CacheObject { OCache oCache = new OCache();
    public static void main(String[] args) {
    CacheObject test = new CacheObject();
    test.init();
    } public void init()
    {
    oCache.setTimeYouxiao(3);//3s
    getStudentById(1);
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    getStudentById(1);
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    getStudentById(1);
    }
    public Object getStudentById(int id) {
    Object result = oCache.getCacheObjectByKey(id+"");
    if(null ==result){
    StudentPojo student= new StudentPojo();
    student.setId(1);
    student.setName("zhangsan");
    oCache.addObject(1+"", student);
    return student;
    }
    return result;
    }
    }class OCache extends ICache { public synchronized HashMap getMap() {
    return map;
    } public synchronized void addObject(String key, Object object) {
    System.out.println("添加了缓存,因为缓存失效或者第一次添加对象");
    put(key, object);
    } public synchronized Object getCacheObjectByKey(String key) {
    return get(key);
    }
    }abstract class ICache { protected long timeYouxiao;
    protected boolean isUseing; protected HashMap<String, CachePack> map = new HashMap<String, CachePack>(); public void put(String key, Object object) {
    map.put(key,
    new CachePack(System.currentTimeMillis(), System
    .currentTimeMillis() + timeYouxiao * 1000, key, object));
    } public Object get(String key) {
    if(map.get(key)!=null && isShiXiao(key))
    {
    System.out.println("使用了缓存");
    }
    return map.get(key)==null || !isShiXiao(key)?null:(map.get(key).getObject());
    } public boolean isShiXiao(String key)
    {
    if(map.get(key).getCurrentTime()-System.currentTimeMillis()>0){
    return true;
    }
    return false;
    }
    public long getTimeYouxiao() {
    return timeYouxiao;
    } public void setTimeYouxiao(long timeYouxiao) {
    this.timeYouxiao = timeYouxiao;
    } public boolean isUseing() {
    return isUseing;
    } public void setUseing(boolean isUseing) {
    this.isUseing = isUseing;
    } public HashMap<String, CachePack> getMap() {
    return map;
    } public void setMap(HashMap<String, CachePack> map) {
    this.map = map;
    }
    }class CachePack { private long savingTime;
    private long currentTime;
    private String key;
    private Object object; public CachePack() {
    } public CachePack(long savingTime, long currentTime, String key,
    Object object) {
    this.savingTime = savingTime;
    this.currentTime = currentTime;
    this.key = key;
    this.object = object;
    } public String getKey() {
    return key;
    } public void setKey(String key) {
    this.key = key;
    } public Object getObject() {
    return object;
    } public void setObject(Object object) {
    this.object = object;
    } public long getSavingTime() {
    return savingTime;
    } public void setSavingTime(long savingTime) {
    this.savingTime = savingTime;
    } public long getCurrentTime() {
    return currentTime;
    } public void setCurrentTime(long currentTime) {
    this.currentTime = currentTime;
    }
    }class StudentPojo { private int id;
    public int getId() {
    return id;
    } public void setId(int id) {
    this.id = id;
    } private String name; public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    } @Override
    public String toString() {
    return "StudentPojo [id=" + id + ", name=" + name + "]";
    }}
      

  13.   

    多线程对应锁住对象实例
    package com.wanju.project001.zonghe.test;import java.util.ArrayList;
    import java.util.List;public class TestThread { public static List aListSetTest=new ArrayList();
    public static void main(String[] args) {
    TestThread testThread = new TestThread();
    testThread.testThread();

    }

    public void testThread()
    {
    aListSetTest.add("eeeeee");
    new Thread(new T()).start();
    try {
    Thread.sleep(3000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    new Thread(new T()).start();
    }

    }
    class T implements Runnable{ @Override
    public void run() {
    synchronized (TestThread.aListSetTest) {
    test(this);
    }
    }
    public  void test(Runnable t)
    {
    while(true)
    {
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("t"+t.toString());
    }
    }
    }tcom.wanju.project001.zonghe.test.T@1cc2ea3f
    tcom.wanju.project001.zonghe.test.T@1cc2ea3f
    tcom.wanju.project001.zonghe.test.T@1cc2ea3f
    tcom.wanju.project001.zonghe.test.T@1cc2ea3f
    tcom.wanju.project001.zonghe.test.T@1cc2ea3f
    tcom.wanju.project001.zonghe.test.T@1cc2ea3f
      

  14.   

    我的理解,缓存的那个
    用concurrentHashMap保存键值就可以
    因为不考虑内存大小限制,所以不设定cache大小,可以让它尽量扩张到接近可以使用的内存如果不求最优方案,我觉得直接用ConcurrentHashMap就OK了,每次加/改数据前,先加/修改Cache里的数据,再持久化数据(比如存入数据库),如果持久化失败,就擦除Cache每次读取数据之前,先读Cache数据,读到就不读持久化的数据,不然再读持久化的数据每次删除数据前,先删Cache,再删持久化里的数据,这个时候可以不考虑回滚--------------------------------------------------------------------------------------------------------
    我不知道这样理解第一题对不对,还是存入Cache的时候它直接就会给我TTL的值,这样的话,就是另外一种思路了
    就是说,我存入Cache的时候,一个存键值,另一个存这个Cache多少时间有效
    这样的话,我还是用ConcurrentHashMap做缓存,给一个put方法,里面存键值和有效时间
    再给一个get方法,有就返回,没有就返回null
    关键是在get方法里要判断拿出来的这个值是否失效了,如果失效,就返回null,并且删掉这个值这样做的话,就不用频繁的去判断是否失效了,到用的时候再去判断我觉得如果再优化的话,可以将删除这个值放在另外一个线程里去异步的做,get只是判断,这样响应更快这是我的理解,请大家一起参与讨论
      

  15.   

    第一个理解不太对。你这样搞就不是缓存了,性能很差的。缓存就是内存操作。关于数据持久化,可以有另一个策略,你可以参考redis的两种持久化策略,但是绝对不是同步的先处理内存在处理持久化,这么搞缓存就没有意义了。第二个理解是可行的。但是操作是有代价的,如果你get的时候再去删,有些key如果不被get就永远占着内存不释放了。不过这些细节都无所谓,毕竟面试笔试都是吹水,随便忽悠都可以
      

  16.   


    谢谢,我也偏向第二种理解我就是觉得它给的条件是内存足够大,所以才选择get的时候去删,这样可以节约删的时间,毕竟对同步的对象操作会有性能开销不知道还有没有更好的办法呢?我担心自己思维有死角
      

  17.   


    谢谢,我也偏向第二种理解我就是觉得它给的条件是内存足够大,所以才选择get的时候去删,这样可以节约删的时间,毕竟对同步的对象操作会有性能开销不知道还有没有更好的办法呢?我担心自己思维有死角异步删,专门搞个线程来维护你的数据集合
      

  18.   


    谢谢,我也偏向第二种理解我就是觉得它给的条件是内存足够大,所以才选择get的时候去删,这样可以节约删的时间,毕竟对同步的对象操作会有性能开销不知道还有没有更好的办法呢?我担心自己思维有死角异步删,专门搞个线程来维护你的数据集合同意,将删数据放另外一个队列里面,用异步的线程专门来删数据
      

  19.   


    其实第一个我的意思是为数据库做的缓存,解释的是怎么协作的我在想,我们平时缓存一般存在多久都是不知道的,就是缓存容量满了就不存了,或者直到被更新和删除一般缓存的容量都是有限的,所以一般的策略就是存放最近使用过的内容,如果最近使用过的内容被命中,那就时间被更新,最先被踢出缓存的就是缓存里最久没有被用到的那个而这里引入了的这个ttl的概念就是time to live,生存周期的概念,似乎我只在DNS域名服务器里碰到过就是DNS查到域名的ip以后,同时会得到一个ttl,然后将这个ip和域名的对应关系缓存在本地(一个人一般一天会访问同一个网站很多次),当ttl指定的时间失效以后,机器就会再次去查询了所以我觉得这里既然引入了ttl,应该也是类似的想法吧,就是加到缓存里的时候就同时有一个过期时间传进来,然后每次查询的时候就判断这个值是否过期,不过期就返回给他,过期就要重新去取了你的理解呢?
    我现在碰到的例子,只有DNS服务器是缓存有
      

  20.   

    刚开始学java,看不太懂,先收藏了
      

  21.   


    其实第一个我的意思是为数据库做的缓存,解释的是怎么协作的我在想,我们平时缓存一般存在多久都是不知道的,就是缓存容量满了就不存了,或者直到被更新和删除一般缓存的容量都是有限的,所以一般的策略就是存放最近使用过的内容,如果最近使用过的内容被命中,那就时间被更新,最先被踢出缓存的就是缓存里最久没有被用到的那个而这里引入了的这个ttl的概念就是time to live,生存周期的概念,似乎我只在DNS域名服务器里碰到过就是DNS查到域名的ip以后,同时会得到一个ttl,然后将这个ip和域名的对应关系缓存在本地(一个人一般一天会访问同一个网站很多次),当ttl指定的时间失效以后,机器就会再次去查询了所以我觉得这里既然引入了ttl,应该也是类似的想法吧,就是加到缓存里的时候就同时有一个过期时间传进来,然后每次查询的时候就判断这个值是否过期,不过期就返回给他,过期就要重新去取了你的理解呢?
    我现在碰到的例子,只有DNS服务器是缓存有
    ttl很多地方都有啊,tcp里就有ttl,redis里也有ttl,缓存怎么可以没有过期时间呢,本地缓存可能没有太多这种概念,但凡是缓存服务器都会有ttl这种概念。实现的机制和优劣分析我上面已经提到过了,你可以再看看。缓存的实现思路,参考redis
      

  22.   

    有点意思,其实跟Java的垃圾回收策略很相似,不过没有这么复杂罢了。
      

  23.   

    although there is not satisfied answer here, finally, i got another job which has a good pay.
    Thank you all.