A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 王海旺 中级黑马   /  2013-7-24 11:59  /  1562 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

线程启动顺序以及什么时候资源共享 什么时候资源不共享???
这个是代码:
public class MyThread extends Thread {
static int a=1;
public void run(){
System.out.println(++a);
}

public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
System.out.println("now a is :"+ ++a);
}
}

输出结果是:
2
4
now a is :3


但是如果把System.out.println("now a is :"+ ++a);这句和那个static修饰符删掉的话
public class MyThread extends Thread {
          int a=1;

public void run(){
System.out.println(++a);
}

public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
}
}

输出结果就变成了:
2
2

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

8 个回复

倒序浏览
这个不固定的,要看那个线程运气好被cup执行。第一个你多执行几次结果都不一样,第二的话就一样了,因为它们使用的不自己的i所以++i后都是2
回复 使用道具 举报
a若是静态变量的话,MyThread这个类所new出来的所有对象都共享a的值!否则MyThread类的每个对象都拥有一个自己的a 不共享

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
  1. public class MyThread extends Thread {
  2. static int a = 1;

  3. public void run() {
  4. try {
  5. sleep(200);
  6. } catch (InterruptedException e) {
  7. // TODO Auto-generated catch block
  8. e.printStackTrace();
  9. }
  10. System.out.println(++a);
  11. }

  12. public static void main(String[] args) {
  13. new MyThread().start();

  14. new MyThread().start();

  15. try {
  16. sleep(500);
  17. } catch (InterruptedException e) {
  18. // TODO Auto-generated catch block
  19. e.printStackTrace();
  20. }
  21. System.out.println("now a is :" + ++a);
  22. }
  23. }
复制代码
new MyThread().start();
new MyThread().start();
2个线程 如果a有static修饰则a是共享的所有会有线程安全问题.
如果没有static修饰则a是2个线程对象各自的不共享没有线程安全问题。
总结:
非静态成员变量在单列的情况下是共享的有线程安全问题,在单列下建议使用局部变量避免线程安全问题如servlet
静态成员变量不管是不是单列都是共享的

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
static int a = 1;这种,两个线程运行run,主线程也在运行,所以,输出的结果肯定不唯一,是看线程运行情况变化的,你多运行几遍就知道了,出现2,4,now is 3这种结果,分析一下,有个线程先执行run,输出了一个2,另一个线程还没执行输出,主线程先执行了输出里的++a,所以主线程应该输出3,这时那另一个线程执行输出,又++a了一次,所以输出了4,然后主线程最后输出了3(这个3之前已经变成参数传递给了println方法了,所以没变),你要是在主线程输出之前sleep(100)毫秒,那输出的就肯定是 2 3 now is 4

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
因为 当创建线程对象时,a是静态变量,会随着类的消失而消失;当再次创建线程对象时,静态变量a还在内存中。
至于输出的结果,会可能有不同的结果。这是因为会有主线程和两个创建的线程,这3个线程在抢占cup资源,这是随机的。所以每次输出的结果不同。
要是去掉static和sop输出语句后,每次创建线程对象后,都会初始化变量a的值。所以每次输出的结果都相。

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 赞一个!

查看全部评分

回复 使用道具 举报
当成员被静态修饰时,那么类加载时候就在方法区存在了,而且此成员只会有一个,也就是被其它资源共享
第一种情况,这个程序中有3个线程,线程0和线程1,还有个主线程都在共享一个成员,所以a的值有3种情况,每次运行,各个线程的值取决于该线程比其它线程先执行还是后执行

而去掉static,那么每new一个对象,这个对象都会有自己的成员a,那么就不存在共享成员的问题了,
第二种情况,每个线程都有自己的a,而且你这线程都是运行一次,所以值都一样

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报

线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.
所有的线程虽然在微观上是串行执行的,但是在宏观上你完全可以认为它们在并行执行
线程的代码区是共享的,即不同的线程可以执行同样的函数。
所以当多个线程同时访问该代码段,改变代码段上的数据时,我们无法确切的知道数据的准确结果,因为我们无法知道某一时有哪几个线程访问了代码段,修改了数据

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
当我们通过start()方法开启这两个线程后,进程中将会有三个线程:主线程(即main线程)和两个匿名对象线程。它们的执行顺序是随机的,任意的,所以输出结果也是不确定的。如果全部按照每个线程执行完,再执行另外一个的方式运行,可能的结果有
(1)2
3
now a is :4
(2)2
now a is :3
4
(3)now a is :2
3
4
如果一个线程没有执行完,就转移到另一个线程执行,那么就可能有很多种结果。而楼主得到的第一种结果,就是这种情况下的一种结果。它的执行过程是:某个匿名线程完全执行,它将a自增,再把它打印,结束。然后主线程也将a自增,这时又转到另一个匿名线程内,将a也自增,然后把它打印,这个匿名线程也结束了。最后主线程执行时,因为自增a已经执行过了,就把它保存的a以前的结果3打印。static修饰的属性是静态的,是所有对象共享的。不加static修饰符的属性是对象独有的,所以第二个程序中的线程操作的是各自对象的a,将各自的a自增,打印的便是各自a的值。

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马