日期:2014-05-20  浏览次数:20706 次

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

正确的代码如下:

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