一个50%的人都不知道多线程调度问题

huangjf2 2010-06-03 07:48:34
我这里有两个类,实现了两个线程,代码程序见下面

class ThreadA {
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
Thread b = new Thread(new ThreadC());
//ThreadC b = new ThreadC();
b.start();

System.out.println("b is start....");
synchronized (b)// 括号里的b是什么意思,起什么作用?
{
try {
//Thread.sleep(20);
//b.setTotal();
System.out.println("Waiting for b to complete...");
b.wait();// 这一句是什么意思,究竟让谁wait?
System.out.println("Completed.Now back to main thread");
} catch (InterruptedException e) {
}
}
}
}


public class ThreadC implements Runnable {
public int total;


public void setTotal(){
total++;
}

public void run(){
synchronized (this) {

System.out.println("ThreadC is running..");
/*try{
Thread.sleep(1000);
}catch(InterruptedException e){}*/
for (int i = 0; i < 20; i++) {
total += i;
System.out.println("total is " + total);
}
notify();
}
}

}


这里执行mian方法已经打印的东西,
b is start....
ThreadC is running..
Waiting for b to complete...
total is 0
total is 1
total is 3
total is 6
total is 10
total is 15
total is 21
total is 28
total is 36
total is 45
total is 55
total is 66
total is 78
total is 91
total is 105
total is 120
total is 136
total is 153
total is 171
total is 190
Completed.Now back to main thread


我这里有一个郁闷的事情,就是从打印ThreadC is running..的时候,那可以看的出来已经进入C线程,而且此时线程拥有此对象的锁(JAVA规定任何时候只有一个线程拥有此对象的锁),但是接着怎么又会打印Waiting for b to complete...呢,这里不是提示A线程也进入这个对象锁了,因为synchronized这个关键字可以获得锁,这样看来不是两个线程同时获得了同一个对象的锁

但是我把public class ThreadC implements Runnable {改成public class ThreadC extends Thread {这个,把Thread b = new Thread(new ThreadC());改成ThreadC b = new ThreadC();,则打印
b is start....
ThreadC is running..
total is 0
total is 1
total is 3
total is 6
total is 10
total is 15
total is 21
total is 28
total is 36
total is 45
total is 55
total is 66
total is 78
total is 91
total is 105
total is 120
total is 136
total is 153
total is 171
total is 190
Waiting for b to complete...
Completed.Now back to main thread

在这里打印我认为是正确的,运用了同一个锁,


忘高手指教了,还是我理解有错误,谢谢,我都郁闷了好几天了,一直想不通
...全文
594 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
happyfish2012 2010-06-05
  • 打赏
  • 举报
回复
路过学习.........
wd9053 2010-06-04
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 fei1703 的回复:]
改了一下代码
notify(); -->this.notify();
就不会通知到主线程了。
这两者还有区别!!!
[/Quote]
我运行结果notify()和this.notify()都一样。。。
wd9053 2010-06-04
  • 打赏
  • 举报
回复
class ThreadA {
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
Thread b = new Thread(new ThreadA());
//ThreadA b = new ThreadA();
b.start();
Object obj = new Object();
System.out.println("b is start....");

Thread c = new Thread();
c.start();
synchronized (c)// 括号里的b是什么意思,起什么作用?
{
try {
//Thread.sleep(20);
//b.setTotal();
System.out.println("Waiting for b to complete...");
c.wait();// 这一句是什么意思,究竟让谁wait?
System.out.println("Completed.Now back to main thread");
} catch (InterruptedException e) {
}
}
}
}


public class ThreadA implements Runnable {
public int total;


public void setTotal(){
total++;
}

public void run(){
synchronized (this) {

System.out.println("ThreadA is running..");
/*try{
Thread.sleep(1000);
}catch(InterruptedException e){}*/
for (int i = 0; i < 20; i++) {
total += i;
System.out.println("total is " + total);
}
notify();
}
}

}

wd9053 2010-06-04
  • 打赏
  • 举报
回复
难道死亡的线程对象不能加锁?
leisore 2010-06-04
  • 打赏
  • 举报
回复

package cn.leisore.daily._2010_06_03;

public class ThreadMain {
public static void main(String[] args) {

final Thread t = new Thread(){
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();

new Thread(){
public void run() {
synchronized (t)
{
try {
t.wait();
System.out.println("t1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();

new Thread(){
public void run() {
synchronized (t)
{
try {
t.wait();
System.out.println("t2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}

输出:
t2
t1

感觉这是一个特例。
即当一个线程实例变量运行结束之后
jvm会notify所有的wait此实例变量的方法??
「已注销」 2010-06-04
  • 打赏
  • 举报
回复
另外
notify()和this.notify()有区别么?
lacus87 2010-06-04
  • 打赏
  • 举报
回复
[Quote=引用 38 楼 l6801567 的回复:]
注意楼主的两个代码段的锁不是同一个
[/Quote]

不是同一个,那么如何保证一个线程执行一半会稳定跳到另外一个执行呢,我测试了几十次都会在这个位置跳出来,而不是随机跳出来
WuBill 2010-06-04
  • 打赏
  • 举报
回复
纯学习。。。。
l6801567 2010-06-04
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 lacus87 的回复:]

我就想知道谁能解释下这个地方:

System.out.println("ThreadC is running..");

-----这里,为什么b线程打印完后就调回主线程而不是继续执行!!-------
for (int i = 0; i < 20; i++) {
total += i;
System.out.println("total is " + total);
}
[/Quote]
注意楼主的两个代码段的锁不是同一个
l6801567 2010-06-04
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 fei1703 的回复:]

我也不理解啊。
Thread b = new Thread(new ThreadC());
这里的b和new ThreadC()应该是不同的对象啊,怎么调用new ThreadC()里的notify会通知到b呢?
[/Quote]
是正解
lacus87 2010-06-04
  • 打赏
  • 举报
回复
我就想知道谁能解释下这个地方:

System.out.println("ThreadC is running..");

-----这里,为什么b线程打印完后就调回主线程而不是继续执行!!-------
for (int i = 0; i < 20; i++) {
total += i;
System.out.println("total is " + total);
}
a87801912 2010-06-04
  • 打赏
  • 举报
回复
有点深,学习中。。。
huangjf2 2010-06-04
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 ciltr 的回复:]

Java code

public class ThreadA {
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
Thread b = new Thread(new ThreadC());// 注……
[/Quote]

那为什么ThreadC后面的notify(),存在不存在可以回到主线程啊,麻烦能否说下JAVA的线程模型啊
ciltr 2010-06-04
  • 打赏
  • 举报
回复

public class ThreadA {
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
Thread b = new Thread(new ThreadC());// 注意这里有两个对象,一个是Thread类型的b,一个是ThreadC类型的匿名对象。
// ThreadC b = new ThreadC();
b.start();

System.out.println("b is start....");
synchronized (b)// 这里是一个b的同步块(不明白就百度一下)
{
try {
// Thread.sleep(20);
// b.setTotal();
System.out.println("Waiting for b to complete...");
b.wait();// 让获得b对象锁的当前线程wait,在这里即本线程。
System.out.println("Completed.Now back to main thread");
} catch (InterruptedException e) {
}
}
}
}

class ThreadC implements Runnable {
public int total;

public void setTotal() {
total++;
}

public void run() {
synchronized (this) {// 这个同步块加到上面提到的匿名对象上了,并没有加到外围的b上面。这就是为什么LZ觉得两个线程同时获得了同一个对象的锁(其实是不同的两个对象,所以两个线程能够同时进入)。

System.out.println("ThreadC is running..");
/*
* try{ Thread.sleep(1000); }catch(InterruptedException e){}
*/
for (int i = 0; i < 20; i++) {
total += i;
System.out.println("total is " + total);
}
notify();
}
}

}

这就很明显了,当ThreadC implements Runnable的时候,两个同步块分别加到Thread类型对象和ThreadC类型对象,这是两个不同的对象,所以两个线程能够分别同时进入这两个同步块。
而把ThreadC修改为继承Thread类之后,两个同步块加在了同一个对象上,结果就可想而知了吧。
jiazimo 2010-06-04
  • 打赏
  • 举报
回复
Runnable Thread 学习!!
BigKing911 2010-06-04
  • 打赏
  • 举报
回复
学习了
xiesisi3 2010-06-04
  • 打赏
  • 举报
回复
xuexi.
忘年之 2010-06-04
  • 打赏
  • 举报
回复
留底。
fei1703 2010-06-04
  • 打赏
  • 举报
回复
当然这个notify加与不加一个样
fei1703 2010-06-04
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 wd9053 的回复:]
Java code
class ThreadA {
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
Thread b = new Thread(new ThreadA());
……
[/Quote]
我错了。。。估计是主线程在wait之前,子线程已经notify了。。。
[Quote=引用 23 楼 wd9053 的回复:]
难道死亡的线程对象不能加锁?
[/Quote]
这个好像就点道理,有什么理论依据吗?
加载更多回复(22)

62,616

社区成员

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

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