一、这段代码大多数状况下运行正常,可是某些状况下会出问题。何时会出现什么问题?如何修正?css
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);这句代码有可能引起数组下标越界html
缘由(答案来源互联网,非本人回答):
假设其中一种情形呵!出问题的情形可能不少,但原理都差很少。下面的标号表明程序时序的前后顺序。
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),越界错误就产生了。java
改进:git
改进1,——最小代码改动,就在remove以前再检查list.size==0
改进2,——去掉push和pop方法内的第二重锁检查,我确实没有发现这个锁会有什么用,反而耗性能。 固然这里仍是要有方案1的判断(谢谢一楼提醒)。
改进3,——从新设计,若是是我来设计这么一个生产者,消费者模式。我更愿意用LinkedBlockingQueue,它有take方法阻塞消费者直到队列可用。并且还有offer方法阻塞生产者直到队列能够插入,能够有效的阻止OOM。数据库
二、写一段代码实现银行转账功能,从转出账号中扣除转账金额,给转入账号增长转账金额,保证两个操做 要么同时成功,要么同时失败数组
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); }
这道题考察对事务的理解。若是转出和转入操做都在同一个应用里面进行,使用数据库的事务特性就能够作到“要么同时成功,要么同时失败”;不然就要用分布式事务的方案来解决,先消化一下这篇文章《分布式系统事务一致性解决方案》。分布式
三、实现统计某一目录下每一个文件中出现的字母个数、数字个数、空格个数及行数?性能
/*文本内容仅限数字,字母,及空格*/ 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 ); } } }
四、假若有字符串“6sabcsfs33” ,用最有快速的方法去掉字符“ab3”,不能用java内置字符串方法(indeOf,substring,replaceAll等)this
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()); }