首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

初学者的多线程有关问题

2013-12-13 
菜鸟的多线程问题我模仿者写买票的程序,结果,发现一个有意思的现象,但自己解释不了,求指教!正确的代码如下

菜鸟的多线程问题
我模仿者写买票的程序,结果,发现一个有意思的现象,但自己解释不了,求指教!

正确的代码如下:


public class Thread1 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable() ;
Thread t1 = new Thread(mr,"线程-1") ;
Thread t2 = new Thread(mr,"线程-2") ;
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(;k>0;){
if( k == 0 )
System.out.println("当前线程["+Thread.currentThread().getName()+"]没票了");
System.out.println("当前线程["+Thread.currentThread().getName()+"]卖出票,还有的数量:"+(k--));
}
}
private int k = 10;
}

结果比如:

当前线程[线程-2]卖出票,还有的数量:10
当前线程[线程-2]卖出票,还有的数量:9
当前线程[线程-2]卖出票,还有的数量:8
当前线程[线程-2]卖出票,还有的数量:7
当前线程[线程-2]卖出票,还有的数量:6
当前线程[线程-2]卖出票,还有的数量:5
当前线程[线程-2]卖出票,还有的数量:4
当前线程[线程-2]卖出票,还有的数量:3
当前线程[线程-2]卖出票,还有的数量:2
当前线程[线程-2]卖出票,还有的数量:1

都是线程-2工作,被卖的数量没错!

但是,如果我把MyRunnable类中的 int k = 10 ;放进for循环中,例如:

class MyRunnable implements Runnable{
@Override
public void run() {
for(int k = 10 ;k>0;){
if( k == 0 )
System.out.println("当前线程["+Thread.currentThread().getName()+"]没票了");
System.out.println("当前线程["+Thread.currentThread().getName()+"]卖出票,还有的数量:"+(k--));
}
}
}

程序就有问题了,明明只有10张票,却执行了20次,结果如下:

当前线程[线程-2]卖出票,还有的数量:10
当前线程[线程-2]卖出票,还有的数量:9
当前线程[线程-2]卖出票,还有的数量:8
当前线程[线程-2]卖出票,还有的数量:7
当前线程[线程-2]卖出票,还有的数量:6
当前线程[线程-2]卖出票,还有的数量:5
当前线程[线程-2]卖出票,还有的数量:4
当前线程[线程-2]卖出票,还有的数量:3
当前线程[线程-2]卖出票,还有的数量:2
当前线程[线程-2]卖出票,还有的数量:1
当前线程[线程-1]卖出票,还有的数量:10
当前线程[线程-1]卖出票,还有的数量:9
当前线程[线程-1]卖出票,还有的数量:8
当前线程[线程-1]卖出票,还有的数量:7
当前线程[线程-1]卖出票,还有的数量:6
当前线程[线程-1]卖出票,还有的数量:5
当前线程[线程-1]卖出票,还有的数量:4
当前线程[线程-1]卖出票,还有的数量:3
当前线程[线程-1]卖出票,还有的数量:2
当前线程[线程-1]卖出票,还有的数量:1


------------------
问:为什么只是把 int k =0 放进了for()循环初始化时,2个线程就使得run运行了20次而不是10次呢?
[解决办法]
 for(int k = 10 ;k>0;){}


简单来说,线程t1,执行10次 k=10,k=9,k=8...
线程t2,执行10次 k=10,k=9,k=8...

楼主加断点DEBUG下,自己看比较清楚

[解决办法]
你这样肯定有问题啊,每个线程都执行一个单独的实例。 就是说你线程一里面的k和你线程二里面的k根本就不是一个。
你要把k放到一个公共区里面,而且还要加锁
[解决办法]
你这个k==0 应该放下面吧,不然没票打印不出。
  public void run() {
    for(;k>0;){
            System.out.println("当前线程["+Thread.currentThread().getName()+"]卖出票,还有的数量:"+(k--));
            if( k == 0 )
                System.out.println("当前线程["+Thread.currentThread().getName()+"]没票了");
        }
    }


都是线程-2工作,被卖的数量没错!---->  这个你多运行几次会发现有1 的线程 。
[解决办法]
因为k在for循环中时,是局部变量,并不是两个线程共享的,而是独立的。而第一情况k是实例变量,两个线程的Runnable实例对象相同,访问的是同一个实例变量k。
[解决办法]
引用:
你这样肯定有问题啊,每个线程都执行一个单独的实例。 就是说你线程一里面的k和你线程二里面的k根本就不是一个。
你要把k放到一个公共区里面,而且还要加锁

哦,看错了。用的一个对象,你把k改成1000再试一下呢
[解决办法]
能出现第一种情况真是侥幸

k为成员变量时会出现资源竞争的问题,此时需要对共享资源进行同步(synchronized or lock)

建议看一下线程状态和CPU调度相关资料


引用:
你这个k==0 应该放下面吧,不然没票打印不出。
  public void run() {
    for(;k>0;){
            System.out.println("当前线程["+Thread.currentThread().getName()+"]卖出票,还有的数量:"+(k--));
            if( k == 0 )
                System.out.println("当前线程["+Thread.currentThread().getName()+"]没票了");
        }
    }


都是线程-2

工作,被卖的数量没错!---->  这个你多运行几次会发现有1 的线程 。


[解决办法]
引用:
Quote: 引用:

你这样肯定有问题啊,每个线程都执行一个单独的实例。 就是说你线程一里面的k和你线程二里面的k根本就不是一个。
你要把k放到一个公共区里面,而且还要加锁

哦,看错了。用的一个对象,你把k改成1000再试一下呢

k这样写的话肯定会有脏数据
[解决办法]
引用:
Quote: 引用:

能出现第一种情况真是侥幸

k为成员变量时会出现资源竞争的问题,此时需要对共享资源进行同步(synchronized or lock)

建议看一下线程状态和CPU调度相关资料


1、k成为成员变量时会出现资源竞争?书上没写,能否解释下?
2、我的k成为for的临时变量时,到是没竞争了,可是咋多运行了一倍!我个人觉得,两个线程引用一个Runnable中的run(),那么怎么会引用出2倍?


每个线程都有自己的栈,用来存储线程中的本地变量,也就是变量k,t1和t2分别拥有自己的栈信息,
分别保存了本地变量k的副本,互不影响,所以各打印10次
[解决办法]
引用:
Quote: 引用:

能出现第一种情况真是侥幸

k为成员变量时会出现资源竞争的问题,此时需要对共享资源进行同步(synchronized or lock)

建议看一下线程状态和CPU调度相关资料


1、k成为成员变量时会出现资源竞争?书上没写,能否解释下?
2、我的k成为for的临时变量时,到是没竞争了,可是咋多运行了一倍!我个人觉得,两个线程引用一个Runnable中的run(),那么怎么会引用出2倍?


第一个问题
当k是成员变量时,t1 t2指向一块内存,也就是变量k,而不是在各自的栈中保存k的副本,
此时就是对变量k的竞争,如果当t1改变了k的值,此时,t1挂起,CPU调度t2执行,则t2得到的是被t1改变了的k的值,这就与预期想得到的值不符
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

你这样肯定有问题啊,每个线程都执行一个单独的实例。 就是说你线程一里面的k和你线程二里面的k根本就不是一个。
你要把k放到一个公共区里面,而且还要加锁

哦,看错了。用的一个对象,你把k改成1000再试一下呢


也就是说,那个k变了?
可是,t1和t2是引用同一个Runnable中的run方法啊?那么他们引用的run()里面的内容也该相同吧?
这就是我问题的根本想问的!

两个线程引用的同一个任务对象 mr,所以k中共用的。然后你run方法肯定是每个线程都有一个自己的run方法,你可以在run里面定义一个自加变量测一下,看一下每个线程是不是的变量是不是独立的。

热点排行