菜鸟的多线程问题
我模仿者写买票的程序,结果,发现一个有意思的现象,但自己解释不了,求指教!
正确的代码如下:
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改成1000再试一下呢
[解决办法]
能出现第一种情况真是侥幸
k为成员变量时会出现资源竞争的问题,此时需要对共享资源进行同步(synchronized or lock)
建议看一下线程状态和CPU调度相关资料
[解决办法]
k这样写的话肯定会有脏数据
[解决办法]
能出现第一种情况真是侥幸
k为成员变量时会出现资源竞争的问题,此时需要对共享资源进行同步(synchronized or lock)
建议看一下线程状态和CPU调度相关资料
1、k成为成员变量时会出现资源竞争?书上没写,能否解释下?
2、我的k成为for的临时变量时,到是没竞争了,可是咋多运行了一倍!我个人觉得,两个线程引用一个Runnable中的run(),那么怎么会引用出2倍?
每个线程都有自己的栈,用来存储线程中的本地变量,也就是变量k,t1和t2分别拥有自己的栈信息,
分别保存了本地变量k的副本,互不影响,所以各打印10次
[解决办法]
能出现第一种情况真是侥幸
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的值,这就与预期想得到的值不符
[解决办法]
你这样肯定有问题啊,每个线程都执行一个单独的实例。 就是说你线程一里面的k和你线程二里面的k根本就不是一个。
你要把k放到一个公共区里面,而且还要加锁
哦,看错了。用的一个对象,你把k改成1000再试一下呢
也就是说,那个k变了?
可是,t1和t2是引用同一个Runnable中的run方法啊?那么他们引用的run()里面的内容也该相同吧?
这就是我问题的根本想问的!
两个线程引用的同一个任务对象 mr,所以k中共用的。然后你run方法肯定是每个线程都有一个自己的run方法,你可以在run里面定义一个自加变量测一下,看一下每个线程是不是的变量是不是独立的。