本帖最后由 杨远 于 2013-1-8 00:09 编辑
在学习初期遇到的问题,因为家里没网,就先记下了。现在发出来,求解惑。。。
问题描述:这是我在写死锁代码时遇到的问题,但是问题不是关于死锁的,而是对象建立和new关键字的问题。
代码如下:- class Test
- {
- public static void main(String[] args)
- {
- new Thread(new DeadLock(true)).start();
- new Thread(new DeadLock(false)).start();
- }
- }
- class DeadLock implements Runnable
- {
- Object obj1 = new Object();
- Object obj2 = new Object();
- // private Object obj1;
- // private Object obj2;
- private boolean flag;
- DeadLock(boolean flag)
- {
- this.flag = flag;
- // obj1 = new Object();
- // obj2 = new Object();
- }
- public void run()
- {
- // 测试10。
- // int x = 1;
- // while (x<2)
- // {
- // System.out.println(obj1.equals(obj2));
- // System.out.println(obj2.equals(obj1));
- // x+=1;
- // }
- if(flag)
- {
- while(true)
- {
- synchronized(obj1)
- {
- System.out.println(Thread.currentThread().getName()+"..if obj1 ");
- synchronized(obj2)
- {
- System.out.println(Thread.currentThread().getName()+"..if obj2");
- }
- }
- }
- }
- else
- {
- while(true)
- {
- synchronized(obj2)
- {
- System.out.println(Thread.currentThread().getName()+"......else obj2");
- synchronized(obj1)
- {
- System.out.println(Thread.currentThread().getName()+"......else obj1");
- }
- }
- }
- }
- }
- }
复制代码 /*
测试:
1. 不用静态修饰,synchronized后使用obj1,obj2。
结果:编译通过,运行无法出现死锁。
2. 将定义的两个对象(锁)obj1,obj2用static修饰,然后用类名调用。(老师示例做法)
结果:编译通过,可以死锁。
3. 将两个锁改为 DeadLock.class和 Test.class 。
结果:编译通过,可以死锁。
把其中一个如 DeadLock .class 换成非静态的 obj1 。
结果:编译通过,运行无法出现死锁。
4. synchronized后的括号里为空。
结果:编译失败。
Test.java:24: 错误: 非法的表达式开始
synchronized()
^
1 个错误
5. 改为 x 。
结果:编译失败。
Test.java:32: 错误: 找不到符号
synchronized(x)
^
符号: 变量 x
位置: 类 DeadLock
1 个错误
6. 定义变量 int m; int n; (boolean,char等相同情况)
结果:编译失败。
Test.java:86: 错误: 意外的类型
synchronized(m)
^
需要: 引用
找到: int
7. 定义引用数据类型的变量。数组。
结果:编译通过,运行无法出现死锁。
8. 定义 String m; String n;
结果:编译通过,提示空指针异常。
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.NullPointerException
at DeadLock .run(Test.java:110)
at java.lang.Thread.run(Thread.java:722)
java.lang.NullPointerException
at DeadLock .run(Test.java:96)
at java.lang.Thread.run(Thread.java:722)
赋值后。 String m = "0"; String n = "1";
结果:编译通过,可以死锁。
改为 String m = "1"; String n = "1";
结果:编译通过,运行无法出现死锁。
9. 在DeadLock 类中建立对象:DeadLock a = new DL(); DeadLock b = new DL(); synchronized的锁换成a和b。
结果:编译通过,运行出现Error。
Exception in thread "main" java.lang.StackOverflowError
at DL.<init>(Test.java:48)
at DL.<init>(Test.java:48)
at DL.<init>(Test.java:48)
在以前的视频里好像见过这个Error,但是忘记了这是什么!
12.13日看到第20天07的视频中,也出现了这样的异常。知道了,StackOverflowError是内存溢出。
10. 在run方法内同步代码块前面加上这样一段代码
int x = 1;
while (x<2)
{
System.out.println(obj1.equals(obj2));
System.out.println(obj2.equals(obj1));
x+=1;
}
这样,要调用方法,对象肯定会创建的吧?
但是运行后,这两条比较的输出语句有输出,但是仍然没有出现死锁。
主问题:
问题与分析:
1是我最开始的写法,对比老师的示例后发现,差别在于我是定义类然后直接调用,老师的是静态后类名调用。
对于一直运行无法出现死锁的情况。那么应该是两种情况:没有锁,或者锁是同一个。
对于是否是锁相同,由3可知,问题在于obj1 没有锁的功能。
回头想,这可能是我的Java基础哪里出现了问题。
从上面推出应该是这句“Object obj1 = new Object();”不在主线程中所有其实并没有建立对象。
但是通过不同情况的试验就发现以下几点不明白:
通过4和5可以看出,Object obj1 这个定义变量是实现了的。
有new关键字。为什么没有建立对象呢?
如果建立了,那么不同类中可以static修饰后用类名调用对象,同类中为什么不可以直接调用呢?
总结与思考:
要关注的:
试验2和试验8的道理。
解释:
2: 类都有自己对应的字节码文件对象。
8: 对象作为锁的功能时需要被判定是否相同
<--对象是否相同,即是否在同一个堆内存中。
<--判定对象所在堆内存的地址,即比较数值。
String判定的也是数值是否相同。所有String可以用作同步的锁。
或者说这个也是对象,String m = new String("0");
//第二天正好看到API这里。所有的双引号括起 "x" 都是对象,就直接用 "0" 和 "1" 作为锁,没有问题。
要注意的:
试验9的Error。所反应出的问题。
思考:哪些情况会导致内存溢出(StackOverflowError)?
另外一个问题:
经过测试
new Thread(new DL(true)).start();
new Thread(new DL(true)){}.start();
都可以正确运行。
那么这两个的区别是什么?
*/
|