zoukankan      html  css  js  c++  java
  • Java面试题和解答(三)

    1、这段代码大多数情况下运行正常,但是某些情况下会出问题。什么时候会出现什么问题?如何修正?

    public class MyStack {  
        private List<String> list = new ArrayList<String>();  
      
        public synchronized void push(String value) {  
            synchronized (this) {  
                list.add(value);  
                notify();  
            }  
        }  
      
        public synchronized String pop() throws InterruptedException {  
            synchronized (this) {  
                if (list.size() <= 0) {  
                    wait();  
                }  
                return list.remove(list.size() - 1);  
            }  
        }  
    }

    list.remove(list.size() - 1);这句代码有可能引发数组下标越界

    原因(答案来源互联网,非本人回答):
    假设其中一种情形呵!出问题的情形可能很多,但原理都差不多。下面的标号代表程序时序的先后顺序。
    1,初始化时list的值为0,然后线程1调用了pop,于是被wait了,然后释放了锁。
    2,线程2调用push,在notify之前有线程3调用pop(记住这时候线程1还没有被唤醒,还在wait住),此时线程3会因为等待锁而挂起,或自旋,反正就是在等待锁可用。
    3,然后线程2继续往下执行,notify被执行(但这时候线程1是不会唤醒的,因为锁还在线程2占用),线程2退出push方法,释放内置锁,此时,线程1和线程3都在内置锁等待队列里面。由于synchronized是没法保证线程竞争的公平性,所以线程1和线程3都可能得到锁。
    4,假设线程1竞争到了锁,不会出问题,正常去除list值,然后remove,执行完后线程3执行,同样被wait住。
    5,假设线程3竞争到了锁,问题来了,线程3会判断到list的size不为0,于是remove,所以list的size就为0了,然后线程 3释放锁,这时候,线程1就得到锁,于是从wait中醒来,继续执行,然后直接调用list的remove,由于list的size=0,那么remove(-1),越界错误就产生了。

    改进:

    改进1,——最小代码改动,就在remove之前再检查list.size==0
    改进2,——去掉push和pop方法内的第二重锁检查,我确实没有发现这个锁会有什么用,反而耗性能。 当然这里还是要有方案1的判断(谢谢一楼提醒)。
    改进3,——重新设计,如果是我来设计这么一个生产者,消费者模式。我更愿意用LinkedBlockingQueue,它有take方法阻塞消费者直到队列可用。而且还有offer方法阻塞生产者直到队列可以插入,可以有效的阻止OOM。

    2、写一段代码实现银行转帐功能,从转出帐号中扣除转帐金额,给转入帐号增加转帐金额,保证两个操作 要么同时成功,要么同时失败

    public interface ITransfer {
        /**
       * fromAccountId  转出帐号 toAccountId 转入帐号 amount 转帐金额
         **/
    
        public void transferInner(String fromAccountId, String toAccountId, BigDecimal amount);
    
        /**
         * 外部转帐-转出,从转出帐号中扣除转帐金额 fromAccountId 转出帐号 amount 转帐金额
         **/
        public void transferOut(String fromAccountId, BigDecimal amount);
    
        /**
         * 外部转帐-转入,给转入帐号增加转帐金额 toAccountId 转入帐号 amount 转帐金额
         */
    
        public void transferIn(String toAccountId, BigDecimal amount);
    }

    这道题考察对事务的理解。如果转出和转入操作都在同一个应用里面进行,使用数据库的事务特性就可以做到“要么同时成功,要么同时失败”;否则就要用分布式事务的方案来解决,先消化一下这篇文章《分布式系统事务一致性解决方案》。

    3、实现统计某一目录下每个文件中出现的字母个数、数字个数、空格个数及行数?

    /*文本内容仅限数字,字母,及空格*/
    import java.io.*;
    class Ex6_5 {
        public static void main ( String[] args ) {
            String fileName = "C:/Hello.txt" , line;
            int i,j,f,k;
            try {
                 BufferedReader in = new BufferedReader(new FileReader( fileName  ) );
                 line = in.readLine();   //读取一行内容
                 while ( line != null ) { 
                        if(Character.isLetter(line))
                          i++;
                       else if(Character.isDigit(line))
                          j++;
                     else
                          f++;    
               line = in.readLine();
                          k++   
                     }
                in.close(); 
            System.out.println("字母"+i+"数字"+j+"空格"+j+"行数"+k)
            }
           catch ( IOException iox ) { 
                System.out.println("Problem reading " + fileName );  
            }
        }
    }

    4、假如有字符串“6sabcsfs33” ,用最有快速的方法去掉字符“ab3”,不能用java内置字符串方法(indeOf,substring,replaceAll等)

      String regx = "[^a|b|3]";
      String temp = "6sabcsssfsfs33";
      Pattern p = Pattern.compile(regx);
      Matcher m = p.matcher(temp);
      while (m.find()) {
       System.out.print(m.group());
      }


  • 相关阅读:
    Mermaid | 强大的画图渲染脚本
    Tools | windows剪切板增强版
    Eclipse | eclipse食用教程
    WebSites | 常用工具网站
    Extensions | Extension && Plugins
    Java | IDE-Eclipse下载安装
    敲个采药玩玩
    今日sb题之 sdnuoj 1064
    stl概述
    给定 n 个字符串,求有多少字符串是其他字符串的前缀。
  • 原文地址:https://www.cnblogs.com/xiaoyangjia/p/4809764.html
Copyright © 2011-2022 走看看