三道中级开发工程面试题

X元素 2017-02-15 11:09:19
给大家来一波中级三道题。
1.
代码 证明HashMap是不安全的而HashTable是安全的。
2.

/**
* Created by does on 17/2/15.
*/
public class Super {

public static void main(String[] args) {
Super aSuper = new Super();
Sub sub =(Sub) aSuper;
}

}
class Sub extends Super{

}

3.
/**
* Created by does on 17/2/15.
*/
public class Test {

public static void main(String[] args) {
Test test = new Test();
try {
test.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
...全文
895 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
戎码一生灬 2017-08-30
  • 打赏
  • 举报
回复
引用 4 楼 pany1209 的回复:
1.HashMap多线程进行操作时由于hash冲突和resize造成数据的丢失,而hashTable的方法是使用synchronized修饰,是安全的 2.这是向下转型的不安全的情况,编译不会报错,运行会出现类转换错误,Super aSuper = new Super();改成Super aSuper=new Sub()就可以了 3.报错。。。没有锁
小怪兽vs69 2017-02-24
  • 打赏
  • 举报
回复
这个很简单啊,,用HashMap里的随便一个方法都可以证明: new 1000个线程,向同一个HashMap对象中put100个值,,多次执行时,最终执行结果,HashMap的size有的时候不是100,而是大于100的数据,打印出map对象,发现,里边存在相同的key,,这是错误的,是线程不安全导致的。而Hashtable不会出现这种情况,而且执行的结果也是有序的。同现可以用这种方法证明ArrayList的线程不安全性,然而且看源码也能看出来,HashMap的put方法,每次拿到key后,调用对象的hashcode方法,再经过一系列^算法再&,得出的Entry数组的位置,贴出JDK7的put源码如下: if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; 这大概意思,就是看看这个Entry对象是不是存在,如果存在,就替换原来的值(这也是为什么HashMap中不能有相同key的原因,单线程情况下) 想象一样,如果多线程的情况下,如果同时,现在有两个线程,一个线程判断出,HashMap中还不存,就会向下走, 走到 addEntry(hash, key, value, i);之前,另一个线程也进来了,发现也没有,两个线程同时会走到 addEntry(hash, key, value, i)方法里,去new Entry数,就导致,HashMap中存在了相同key的数据了,,这肯定就不对了啊。,,测试代码自己去写吧,实在不会,就再找我,我给你贴出来。。赶紧滴,把分分给我吧,哈哈
  • 打赏
  • 举报
回复
逻辑很清楚啊,线程可以共享数据这是多线程机制决定的,只要多个线程对共享数据进行了非原子操作,这是写的代码决定的,就有可能产生问题,所以要有同步。
逗泥丸的平方 2017-02-17
  • 打赏
  • 举报
回复
引用 6 楼 lonrence 的回复:
[quote=引用 5 楼 qq_35209952 的回复:] [quote=引用 3 楼 lonrence 的回复:] 1、HashMap多线程并发操作会产生数据异常,HashTable不会,因为HashTable的方法是同步方法,虽然安全但会损失效率。 2、编译成功,运行抛出异常。对于编译器来说Super有子类Sub,强制类型转换是认可的,但运行时会报类型转换错误。 3、调用父类Object的方法,语法上没问题,编译应该可以成功,但是wait方法,将建立锁对象的等待池,这里缺少了锁对象,运行时也会报错。
第一题要写代码呢/..\ 虽然说瞎写肯定也会出错, 不过不知道 能不能写出来一个一定出问题的情况...[/quote]
public class HashMapDemo {
	public static void main(String[] args) {
		final HashMap<Integer, Integer> map = new HashMap<>();
		for (int i = 0; i < 100000; i++) {
			map.put(i, i);
		}
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					for (int j = 999; j < 1005; j++) {
						System.out.println(Thread.currentThread().getName() +" " + map.remove(j));
					}
				}
			}).start();
		}
	}
}
从map中删除几个数据,如果是线程安全的,只要删一次即可,但HashMap,有可能会删除数次,还是因为remove方法不是原子操作,当某个线程从map中找到了数据,但被剥夺了执行权,同时另外一个线程完成了删除,该线程恢复,继续操作,造成了数据错误。[/quote] 我也知道这样写可以.. 但是实际上这个证明是从"经验"上来推断的事实, 而不是从逻辑上来否定的.
  • 打赏
  • 举报
回复
2 个线程即可
  • 打赏
  • 举报
回复
引用 5 楼 qq_35209952 的回复:
[quote=引用 3 楼 lonrence 的回复:] 1、HashMap多线程并发操作会产生数据异常,HashTable不会,因为HashTable的方法是同步方法,虽然安全但会损失效率。 2、编译成功,运行抛出异常。对于编译器来说Super有子类Sub,强制类型转换是认可的,但运行时会报类型转换错误。 3、调用父类Object的方法,语法上没问题,编译应该可以成功,但是wait方法,将建立锁对象的等待池,这里缺少了锁对象,运行时也会报错。
第一题要写代码呢/..\ 虽然说瞎写肯定也会出错, 不过不知道 能不能写出来一个一定出问题的情况...[/quote]
public class HashMapDemo {
	public static void main(String[] args) {
		final HashMap<Integer, Integer> map = new HashMap<>();
		for (int i = 0; i < 100000; i++) {
			map.put(i, i);
		}
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					for (int j = 999; j < 1005; j++) {
						System.out.println(Thread.currentThread().getName() +" " + map.remove(j));
					}
				}
			}).start();
		}
	}
}
从map中删除几个数据,如果是线程安全的,只要删一次即可,但HashMap,有可能会删除数次,还是因为remove方法不是原子操作,当某个线程从map中找到了数据,但被剥夺了执行权,同时另外一个线程完成了删除,该线程恢复,继续操作,造成了数据错误。
逗泥丸的平方 2017-02-17
  • 打赏
  • 举报
回复
引用 9 楼 lonrence 的回复:
逻辑很清楚啊,线程可以共享数据这是多线程机制决定的,只要多个线程对共享数据进行了非原子操作,这是写的代码决定的,就有可能产生问题,所以要有同步。
呃.. 仔细看了一下这个代码,好像和想象中的不太一样.. 这段代码的运行结果是什么样的?替换成hashtable之后,差别在哪里?
  • 打赏
  • 举报
回复
1、HashMap多线程并发操作会产生数据异常,HashTable不会,因为HashTable的方法是同步方法,虽然安全但会损失效率。 2、编译成功,运行抛出异常。对于编译器来说Super有子类Sub,强制类型转换是认可的,但运行时会报类型转换错误。 3、调用父类Object的方法,语法上没问题,编译应该可以成功,但是wait方法,将建立锁对象的等待池,这里缺少了锁对象,运行时也会报错。
七脉 2017-02-16
  • 打赏
  • 举报
回复
1.HashMap之所以是不安全 是指线程问题,多线程高并发时才会可能出现,可以建一百个线程操作同一个HashMap对象就有可能出现失真,丢值现象。原因具体可以参考Hash值与链表的存值方式。 2.应该是强转错误,个人认为父类对象强转子类对象需要一个前提条件。父类引用指向的对象就是子类对象,父类引用的对象才可以强转为子类对象。 3.应该会抛异常,wait 很明显是线程等待,没有多线程同步的对象调取wait是没任何意义的。
逗泥丸的平方 2017-02-16
  • 打赏
  • 举报
回复
第一题得想一下,写着可能没那么快.. 要是面试的话 得算是不会了吧. 第二题是干嘛的... 是指出cast 失败吗? 第三题...哦 这两个是解释原理吗.
逗泥丸的平方 2017-02-16
  • 打赏
  • 举报
回复
引用 3 楼 lonrence 的回复:
1、HashMap多线程并发操作会产生数据异常,HashTable不会,因为HashTable的方法是同步方法,虽然安全但会损失效率。 2、编译成功,运行抛出异常。对于编译器来说Super有子类Sub,强制类型转换是认可的,但运行时会报类型转换错误。 3、调用父类Object的方法,语法上没问题,编译应该可以成功,但是wait方法,将建立锁对象的等待池,这里缺少了锁对象,运行时也会报错。
第一题要写代码呢/..\ 虽然说瞎写肯定也会出错, 不过不知道 能不能写出来一个一定出问题的情况...
李德胜1995 2017-02-16
  • 打赏
  • 举报
回复
1.HashMap多线程进行操作时由于hash冲突和resize造成数据的丢失,而hashTable的方法是使用synchronized修饰,是安全的 2.这是向下转型的不安全的情况,编译不会报错,运行会出现类转换错误,Super aSuper = new Super();改成Super aSuper=new Sub()就可以了 3.报错。。。没有锁

62,635

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧