发现一个多线程很奇怪的问题,急急急!

发现一个多线程很奇怪的问题,急急急!

老师先看这个图:http://img1.sycdn.imooc.com//climg/5da2c45209a9daaa07550850.jpg问题一:我的理解是,这个多线程题分为主线程跟new Thread自己创建的线程(暂且称为副线程),在main方法中运行到t.start这一句开启副线程,顺序先是执行主线程即test.m2();System.out.println(test.b);这两句,在m2方法中把b=2000了,我的理解是m2方法跑完了接着执行System.out.println(test.b);这句,因为这句也是主线程里面的,但是这句话的结果输出的却是1000?为什么呢?这个1000代表着进行完m2之后就把锁给m1就执行m1了,那请问老师正确的执行顺序是什么呢?

问题二:为了验证我上面理解的准确性,我在m2方法中加了一条输出语句,想看b的值,但是结果却是不一定的???

http://img1.sycdn.imooc.com//climg/5da2c5c6092571a906880864.jpg

http://img1.sycdn.imooc.com//climg/5da2c5c6093e9a0f07980864.jpg

这是说明主线程中的System.out.println(test.b);语句跟m1方法是同步线程吗??但是m1不是加了锁吗?不是应该执行完m1再做其他的吗?为什么会出现呢这样的结果呢??

正在回答

登陆购买课程后可参与讨论,去登陆

4回答

同学你好,

  1. 第一个问题,进入main方法线程就会执行

  2. 第二个,如果只是这两个方法的对结果的影响,同学这里可以先不考虑主线程,这样可能会搞混。

    1)如果m1加锁,m2加锁,它们之间不会同时执行,一定是分开的,同学在之前的测试中也看到了始终是其中一个执行完另一个才执行。也就是同时只能执行一个加了synchronized的方法

    2)如果m2不加锁,它们两个是可以同时执行了,可以看到m1和m2之前穿插着执行了,并且你会发现后m2面尽然也输出了1000,这说明m2修改了数据后,m1也执行了。导致出现了脏数据。

    http://img1.sycdn.imooc.com//climg/5da30386099cfbd608280732.jpg

  3. 所以只有同时加了synchronized的方法不能同时访问,如果有一个没有加,那么

    没有加synchronized的方法不受加了synchronized的方法的影响。因此它们之间都加锁数据正常,如果其中一个不加锁可能会出现脏数据。

  4. 这里同学就可以先忽略主线程打印的问题。(主线程的打印与上面不是一回事),建议同学慢慢来理解,线程的确是有点不太好理解。

如果我的回答解决了你的疑惑,请采纳,祝学习愉快~

好帮手慕柯南 2019-10-13 18:36:14

同学,

  1. 首先一个项目的入口程序肯定是main方法呢,如没有main方法同学的这个例子是跑不起来的。所以一定是main线程先执行

  2. 同学所说的m1和m2 并没有抢占b这个属性呢。你也可以看到m2执行时m1并没有执行,

  3. 是在mian方法中打印输出使用b时,此时另一个线程的m1正在执行所以同时抢占b这个资源呢

    http://img1.sycdn.imooc.com//climg/5da2fdb609dd0f5206860528.jpg

  4. 同学说是面试题,请问面试题是在问同学什么呢?如果同学说明一下。针对性的说明它提问,或许你会更容易明白呢。

如果我的回答解决了你的疑惑,请采纳,祝学习愉快~

  • 提问者 KelvinChung #1
    面试题是说关于锁的问题的哦,就是m1加了锁,m2不加锁,或者都加锁,对最后结果的影响,,那是一进入到main方法中的时候就会启动main的线程了吗?
    2019-10-13 18:49:22
  • 提问者 KelvinChung #2
    老师您先休息吧我先自己捋一捋,打扰您太久了不好意思哦
    2019-10-13 18:56:46
好帮手慕柯南 2019-10-13 17:28:10

同学你好,

  1. 不会给main线程优先分配资源的,它的分配策略是有操作系统决定的。这里只是看起来先给main线程分配的,但是实际上不上的~

  2. 首先抢占资源需要有两个线程同时执行才会出现。我们来分析一下m2方法有几个线程执行了,

    1) t.start();启动线程,也就是执行run方法中的代码,可以看到这个线程其实只执行了m1这个方法

    http://img1.sycdn.imooc.com//climg/5da2ec03092ff8fa03380129.jpg

    2)而m2方法只在main线程中执行了,这说明m2方法只在主线程中执行了

    http://img1.sycdn.imooc.com//climg/5da2ec5509f10c4a01940072.jpg

    3)同学可能会疑问,m1也只在副线程中执行了,为什么他们抢资源了。这里其实是m1(它是一个线程在调度的)需要使用b这个属性,而主线程也需要b这个属性。所以这两个线程出现了谁先获得了cpu,谁就可以操作b的这个属性。这样的资源争夺。

如果我的回答解决了你的疑惑,请采纳,祝学习愉快~

  • 提问者 KelvinChung #1
    哭了老师我还是不懂,那请问老师如果不在ide上运行,这是一道面试题,您是怎么知道先会运行main这个线程呀?还有哦,就是一开始是先跑m2的,m2只在主线程中执行没错呀,那m1也要用到b,是因为m2上了锁所以m1才不能跟m2抢占资源是这样吗?但是m2结束后,就是轮到m1跟main线程里面的 System.out.println("main:"+test2.b);两个互相抢占资源,但是但是m1方法也有加锁诶,不是加了锁之后就别人不能跟它抢了吗??
    2019-10-13 18:22:25
好帮手慕柯南 2019-10-13 16:02:16

同学你好,

  1. 首先来说一下主线程和同学这里所说的副线程,都是线程,其实他们是异步的。

  2. 接下来结合同学的结果来解释一下会更好。

    1.首先运行了main方法开启了main线程

    2.main线程接着往下执行,在t.start();开启了一个副线程。(注意只是开启了,只能说明它具备运行的资格了,但是cpu不一定给他分配了资源)

    3.此时程序中有两个线程在等待cpu分配资源。(分配策略有系统决定)

    4)此时main线程占有资源,因此继续执行下面的test2.m2();此时b=2000,

    5)主线程执行完之后,副线程获得资源开始执行,所以出现了同学看到的,主线程执行完了,m1才执行。其实这里只是争夺资源的问题~所以他们的执行顺序是不一定的。如果项目中的内容比较小,可能会出现一只是一种执行情况的现象

  3. 老师在sleep前后都添加了输出,并且在main方法中将b多输出几次,可以看到b的两个值,还看到了线程资源的争夺。(注意这里只是不能同时执行m1和m2)但是两线程并没有同步

http://img1.sycdn.imooc.com//climg/5da2dabf0954c89512650667.jpg

休眠时的资源抢占

http://img1.sycdn.imooc.com//climg/5da2d9f2097ef69208860768.jpg

4. 老师修改后的代码,同学可以用来试一下

package ceshi;

public class Test2 implements Runnable {
	int b=100;
	public synchronized void m1() throws InterruptedException{
		b=1000;
		System.out.println("m11:"+b);
		Thread.sleep(5000);
		System.out.println("m1:"+b);
	}
	public synchronized void m2() throws InterruptedException{
		b=2000;
		System.out.println("m21:"+b);
		Thread.sleep(1000);
		System.out.println("m2:"+b);
		
	}
	public static void main(String[] args) throws InterruptedException {
		Test2 test2=new Test2();
		Thread t=new Thread(test2);
		
		t.start();
	
		test2.m2();
		for(int  i=0;i<100;i++){
		System.out.println("main:"+test2.b);
		}
		
	}

	public void run() {
		try {
			m1();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

如果我的回答解决了你的疑惑,请采纳,祝学习愉快~

  • 提问者 KelvinChung #1
    谢谢老师那么详细耐心的回复,请问老师:(1)有两个线程在等待cpu分配资源,先给main线程分配是规定的吗?(2)为什么在m2()方法中没有发生抢占资源呢?是因为m2方法中加了锁吗?在把锁交出来之前独占资源?那后面m1()也有加锁呀,为什么main中的 System.out.println("main:"+test2.b);方法会与m1();发生抢占呢?
    2019-10-13 16:35:03
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师