螞蟻金服筆試題

  • 題目一:
    提供一個懶漢模式的單實例類實現。
    要求:
    1.考慮線程安全。
    2.提供測試代碼,測試線程安全性。
public class Singleton {
    public Singleton() {}
    /**
     * 內部靜態類實現單例
     */
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public static void main(String[] args) {
        //測試代碼,驗證50個線程去獲取單例是不是一個實例
        for (int i = 0; i < 50; i++) {
            new Thread(() -> System.out.println(Singleton.getInstance().hashCode())).start();
        }
    }
}
  • 題目二
    1.設計含最小函數min()、pop()、push()的棧AntMinStack,存儲數據元素爲int
    2.AntMinStack中數據存儲使用Stack結構
    要求:
    1.AntMinStack實現測試,滿足棧特性
    2.要求min、push、pop、的時間複雜度都是O(1)
public class AntMinStack {

    Stack<Integer> stack; //存儲值
    Stack<Integer> min;//存儲最小值

    public AntMinStack(){
        stack = new Stack<>();
        min = new Stack<>();
    }

    public void push(int data){
        stack.push(data);
        if (min.isEmpty() || data <= min.peek()){
            min.push(data);
        }
    }
    public int pop() throws Exception{
        if (stack.isEmpty()){
            throw new Exception("EmptyStackException");
        }
        if (stack.peek() == min.peek()){
            min.pop();
        }
        return stack.pop();
    }
    public int min() throws Exception{
        if (min.isEmpty()){
            throw new Exception("EmptyStackException");
        }
        return min.peek();
    }

    public static void main(String[] args) throws Exception{
        AntMinStack antMinStack = new AntMinStack();
        for (int i = 20; i >= 0; i--) {
            antMinStack.push(i);
            System.out.println("入棧:"+i+",最小值爲:"+antMinStack.min());
        }
        for (int i = 0; i < 19; i++) {
            System.out.println("出棧:"+antMinStack.pop()+"最小值爲:"+antMinStack.min());
        }
    }
}
  • 題目三
    假設本地有一個文件夾,文件夾下面有若干文件(文件數大於50小於100),文件的存儲格式是文本格式(後綴名是.txt),文件的大小每個文件不會超過100k
    文件格式如下:
    2000102,100,98.32000103,101,73.32000104,102,98.32000105,100,101.32000106,101,45.3……
    文件格式說明:文件每行都由三列構成,第一列是一個id,第二列是分組groupId, 第三列是指標quota。
    id的數據類型是String, groupId的數據類型String, quota的數據類型float。
    功能要求:1.把所有文件裏面的內容按照分組進行排序,輸出所有文件按照分組升序排序之後,每個分組下面的最小指標值。比如上面的數據輸出結果爲:100,2000102,98.3101,2000106,45.3102,2000104,98.3
    非功能要求:
    1.文件讀取要有線程池來執行,線程池的大小固定爲10,文件內容需要存儲到指定的內容數據結構當中
    2.查找要求有獨立線程來執行,直接消費讀取線程池產生的內存數據結構。
    3.文件讀取和排序要求併發作業,文件讀取只要產生了數據,就可以把數據交給排序線程進行消費,計算最小值。
    代碼要求
    1.重上面的要求語意裏面抽象出合適的設計模式。
    2.需要考慮多線程的併發控制,同步機制。
    3.代碼實現只能用JDK1.6或者1.8自帶的工具類
/**  
 *     
 * 生產者線程
 * Author: Administrator   Date: 2018年8月28日  
 *       
 */
public class Producer implements Runnable{

    private LinkedBlockingQueue<DataItem> queue;
    private File file;
    private CountDownLatch countDownLatch;
    public Producer(LinkedBlockingQueue<DataItem> queue,File file,CountDownLatch countDownLatch) {
        this.queue = queue;
        this.file = file;
        this.countDownLatch = countDownLatch;
    }
    @Override
    public void run() {
        try {
            InputStreamReader read = new InputStreamReader(new FileInputStream(file));
            BufferedReader br=new BufferedReader(read);
            String line="";
            String[] arrs=null;
            while ((line=br.readLine())!=null) {
                if (line.equals("")) {
                    continue;
                }
                arrs=line.split(",");
                DataItem dataItem = new DataItem();
                dataItem.setId(arrs[0]);
                dataItem.setGroupId(arrs[1]);
                dataItem.setQuota(new Float(arrs[2]));
                queue.add(dataItem);
            }
            br.close();
            read.close();
            countDownLatch.countDown();
        } catch (Exception e) {
            e.printStackTrace();
        }   

    }

}
/**  
 *     
 * 消費者線程
 * Author: Administrator   Date: 2018年8月28日  
 *       
 */
public class Consumer implements Runnable{

    private LinkedBlockingQueue<DataItem> queue;
    private TreeMap<String, DataItem> treeMap;
    private CountDownLatch countDownLatch;
    public Consumer(LinkedBlockingQueue<DataItem> queue,TreeMap<String, DataItem> treeMap,CountDownLatch countDownLatch) {
        this.queue = queue;
        this.treeMap = treeMap;
        this.countDownLatch = countDownLatch;
    }
    @Override
    public void run() {
        try {
            while(true){
                if (!queue.isEmpty()) {
                    DataItem dataItem = queue.take();
                    DataItem mydataItem = treeMap.get(dataItem.getGroupId());
                    if (mydataItem == null) {
                        treeMap.put(dataItem.getGroupId(), dataItem);
                    }else{
                        if (dataItem.getQuota() < mydataItem.getQuota()) {
                            treeMap.put(dataItem.getGroupId(), dataItem);
                        }
                    }
                }else{
                    if(countDownLatch.getCount() <= 1){
                        countDownLatch.countDown();
                        break;
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
/**  
 *     
 * 數據倉庫
 * Author: Administrator   Date: 2018年8月29日  
 *       
 */
public class DataWareHouse {

    private static final int THREAD_POOL_SIZE = 10;
    private LinkedBlockingQueue<DataItem> queue;//緩存生產者線程從文件讀取的數據
    private TreeMap<String, DataItem> treeMap;//存儲消費者線程處理後的數據(排序、獲取同組指標最小的數據)
    private ExecutorService threadPool;//線程池
    public DataWareHouse() {
        queue = new LinkedBlockingQueue<>();
        treeMap = new TreeMap<>(new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                return Long.valueOf(o1).compareTo(Long.valueOf(o2));
            }
        });
        threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
    }
    public LinkedBlockingQueue<DataItem> getQueue() {
        return queue;
    }
    public void setQueue(LinkedBlockingQueue<DataItem> queue) {
        this.queue = queue;
    }
    public TreeMap<String, DataItem> getTreeMap() {
        return treeMap;
    }
    public void setTreeMap(TreeMap<String, DataItem> treeMap) {
        this.treeMap = treeMap;
    }
    public ExecutorService getThreadPool() {
        return threadPool;
    }
    public void setThreadPool(ExecutorService threadPool) {
        this.threadPool = threadPool;
    }

}
/**  
 *     
 *  
 * Author: Administrator   Date: 2018年8月28日  
 *       
 */
public class DataItem {

    /**
     * id
     */
    private String id;
    /**
     * 分組
     */
    private String groupId;
    /**
     * 指標
     */
    private Float quota;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getGroupId() {
        return groupId;
    }
    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }
    public Float getQuota() {
        return quota;
    }
    public void setQuota(Float quota) {
        this.quota = quota;
    }

}
public class Main {

    public static void main(String[] args) {
        String dirPath = "src/main/resources/files";
        File dirFile = new File(dirPath);
        File[] files = dirFile.listFiles();
        DataWareHouse dataWareHouse = new DataWareHouse();
        CountDownLatch countDownLatch = new CountDownLatch(files.length + 1);
        for(File file : files){
            Producer producer = new Producer(dataWareHouse.getQueue(), file,countDownLatch);
            //生產者線程使用線程池
            dataWareHouse.getThreadPool().execute(producer);
        }
        Consumer consumer = new Consumer(dataWareHouse.getQueue(), dataWareHouse.getTreeMap(),countDownLatch);
        //一個消費者線程消費
        new Thread(consumer).start();
        try {
            //生產者線程和消費者線程執行完成,關閉線程池,輸出結果
            countDownLatch.await();
            dataWareHouse.getThreadPool().shutdownNow();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Iterator<Entry<String, DataItem>> it = dataWareHouse.getTreeMap().entrySet().iterator();
        while(it.hasNext()) {
            Entry<String, DataItem> entry = it.next();
            DataItem dataItem = entry.getValue();
            System.out.println(dataItem.getGroupId() + "," + dataItem.getId()+","+dataItem.getQuota());
        }
    }
}
/**     
 * 創建測試數據
 * @author jiangpan 
 * @title CreateDataTest.java
 * @date 2018年8月29日 
 *     
 */
public class CreateDataTest {

    public static void main(String[] args) throws IOException {
        String path = "src/main/resources/files/";
        for (int i = 1; i < 100; i++) {
            File file = new File(path+i+".txt");
            if(!file.exists()){
                file.createNewFile();
            }
            FileWriter fileWriter = new FileWriter(file);
            BufferedWriter br = new BufferedWriter(fileWriter);
            for (int j = 0; j < 5000; j++) {
                br.write(getRandomData());
                br.newLine();
            }
            br.close();
            fileWriter.close();

        }
        System.out.println("success");
    }

    private static String getRandomData(){
        Integer id = (int)(Math.random() * 1000000) + 1000000;
        Integer groupId = (int)(Math.random() * 1000) + 100;
        Float quota = (int)(Math.random() * 1000)/10.0f+60;
        return id+","+groupId+","+quota;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章