Thread中的join()方法

在对于join()方法是否会释放"锁标识"问题,可以这样认为,一定要看有无synchronized关键字的前提下,大致分为四种情况:

1.没有synchronized关键字,访问的也不是同一资源

这种情况下是不存在什么锁的,因为访问的不是同一资源,两个不同的对象。那么可以理解成是等待调用join()方法的线程结束,再执行。代码如下:

public class TestThreadJoinMethod implements Runnable {

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+"执行"+i+"次");
		}
	}

}
public class Test {
	public static void main(String[] args) {
		TestThreadJoinMethod t = new TestThreadJoinMethod();
		Thread r = new Thread(t,"线程一");
		r.start();
		for (int i = 0; i < 10; i++) {
			System.out.println("主线程执行到第"+i+"步");
			if(i>2){
				try {
					r.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

执行结果:

主线程执行到第0步
线程一执行0次
主线程执行到第1步
线程一执行1次
主线程执行到第2步
线程一执行2次
主线程执行到第3步
线程一执行3次
线程一执行4次
线程一执行5次
线程一执行6次
线程一执行7次
线程一执行8次
线程一执行9次
主线程执行到第4步
主线程执行到第5步
主线程执行到第6步
主线程执行到第7步
主线程执行到第8步
主线程执行到第9步

结果显示:在join()之前,两个不同的线程一直都是在交叉执行的,争夺CPU执行权。在遇到join()方法后,调用了r的线程直至结束才调用主线程的。

2.没有synchronized关键字,访问的是同一资源

public class TestThreadJoinMethod implements Runnable {

	@Override
	public void run() {//注意这里是没有用synchronized关键字的

		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+"执行"+i+"次");
		}
	}

}
public class Test {
	public static void main(String[] args) {
		TestThreadJoinMethod r = new TestThreadJoinMethod();
		Thread t1 = new Thread(r,"线程一");
		Thread t2 = new Thread(r,"线程二");
		Thread t3 = new Thread(r,"线程三");
		t1.start();
		t2.start();
		try {
			t2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t3.start();
//这里的三个线程都是访问的同一资源,创建对象都是r

结果:

线程一执行0次
线程二执行0次
线程一执行1次
线程二执行1次
线程二执行2次
线程一执行2次
线程二执行3次
线程一执行3次
线程一执行4次
线程一执行5次
线程一执行6次
线程一执行7次
线程一执行8次
线程一执行9次
线程二执行4次
线程二执行5次
线程二执行6次
线程二执行7次
线程二执行8次
线程二执行9次
线程三执行0次
线程三执行1次
线程三执行2次
线程三执行3次
线程三执行4次
线程三执行5次
线程三执行6次
线程三执行7次
线程三执行8次
线程三执行9次

前面线程一和二交叉执行,最后才是线程三执行,因为join()方法出现在线程一和线程三中间,所以,线程三总得等到线程二执行完毕才能执行。

3.有synchronized关键字,访问不是同一资源

//线程一
public class TestThreadJoinMethod implements Runnable {

	@Override
	public synchronized void run() {
		for (int i = 0; i < 10; i++) {
			TestThreadJoinMethod2 joinMethod2 = new TestThreadJoinMethod2();
			Thread c = new Thread(joinMethod2);
			System.out.println(Thread.currentThread().getName()+"执行"+i+"次");
			if(i == 5){
				c.start();
				try {
                                c.join();
                            } catch (InterruptedException e) {
e.printStackTrace();}}}}}//线程二class TestThreadJoinMethod2 implements Runnable{@Overridepublic void run() {System.out.println("我是来插队的");}}
public class Test {
	public static void main(String[] args) {
		TestThreadJoinMethod r = new TestThreadJoinMethod();
		Thread t1 = new Thread(r,"线程一");
		Thread t2 = new Thread(r,"线程二");
		Thread t3 = new Thread(r,"线程三");
		t1.start();
		t2.start();
		t3.start();

结果:

线程一执行0次
线程一执行1次
线程一执行2次
线程一执行3次
线程一执行4次
线程一执行5次
我是来插队的
线程一执行6次
线程一执行7次
线程一执行8次
线程一执行9次
线程三执行0次
线程三执行1次
线程三执行2次
线程三执行3次
线程三执行4次
线程三执行5次
我是来插队的
线程三执行6次
线程三执行7次
线程三执行8次
线程三执行9次
线程二执行0次
线程二执行1次
线程二执行2次
线程二执行3次
线程二执行4次
线程二执行5次
我是来插队的
线程二执行6次
线程二执行7次
线程二执行8次
线程二执行9次

结论:因为两个是访问的不同的锁对象,所以没有释放不释放锁标识这一说。跟第一种情况类似

4.有synchronized关键字,访问的是同一资源

public class TestThreadJoinMethod implements Runnable {

	@Override
	public synchronized void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+"执行"+i+"次");
		}
	}

}

public class Test {
	public static void main(String[] args) {
		TestThreadJoinMethod r = new TestThreadJoinMethod();
		Thread t1 = new Thread(r,"线程一");
		Thread t2 = new Thread(r,"线程二");
		Thread t3 = new Thread(r,"线程三");
		t1.start();
		t2.start();
		t3.start();

结果:

线程一执行0次
线程一执行1次
线程一执行2次
线程一执行3次
线程一执行4次
线程一执行5次
线程一执行6次
线程一执行7次
线程一执行8次
线程一执行9次
线程三执行0次
线程三执行1次
线程三执行2次
线程三执行3次
线程三执行4次
线程三执行5次
线程三执行6次
线程三执行7次
线程三执行8次
线程三执行9次
线程二执行0次
线程二执行1次
线程二执行2次
线程二执行3次
线程二执行4次
线程二执行5次
线程二执行6次
线程二执行7次
线程二执行8次
线程二执行9次

结论:线程三在执行线程二之前,这说明,在第一时间三个线程是一起争夺CPU执行权的,线程一抢到之后,拿到了对象的锁,线程二和线程三只能等待线程一释放锁,才有机会执行。跟抢厕所一个道理。大笑



5.补充一点额外,不用join(),访问同一资源,卖票例子类同。只是突然想到了,就试了一下。跟本题没有关系

public class TestThreadJoinMethod implements Runnable {

	@Override
	public void run() {//注意这里是没有用synchronized关键字的

		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+"执行"+i+"次");
		}
	}

}
public class Test {
	public static void main(String[] args) {
		TestThreadJoinMethod r = new TestThreadJoinMethod();
		Thread t1 = new Thread(r,"线程一");
		Thread t2 = new Thread(r,"线程二");
		Thread t3 = new Thread(r,"线程三");
		t1.start();
		t2.start();
		t3.start();
//这里的三个线程都是访问的同一资源,创建对象都是r

结果如下:

线程一执行0次
线程二执行0次
线程三执行0次
线程三执行1次
线程二执行1次
线程一执行1次
线程一执行2次
线程二执行2次
线程三执行2次
线程二执行3次
线程二执行4次
线程二执行5次
线程二执行6次
线程二执行7次
线程二执行8次
线程一执行3次
线程二执行9次
线程三执行3次
线程三执行4次
线程三执行5次
线程三执行6次
线程一执行4次
线程三执行7次
线程一执行5次
线程三执行8次
线程一执行6次
线程三执行9次
线程一执行7次
线程一执行8次
线程一执行9次

从结果来看,三个线程访问同一个资源,交叉执行,争夺CPU资源。这个跟卖票的例子类同。会出现卖重票的错误。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值