thread 中join() 的用法

本文详细解析了Java中线程控制方法join、sleep、yield的使用方法及区别,并介绍了Object类中的wait与notify方法的作用及其应用场景。

前段时间参加面试时,被一个面试官问到thread中join方法用法,那会自己答得有点唐突吧,面试官对我的回答好像不是很满意!

最近有点小空闲,就稍微看了一些书,然后自己整理了一下线程中几个方法的用法:

1.首先来说说线程Thread的Join方法:

join方法顾名思义 就是往线程中添加东西的;join方法可以用于临时加入线程,一个线程在运算过程中,如果满足于条件,我们可以临时加入一个线程,让这个线程运算完,另外一个线程再继续运行。

看一下一个demo:

/**
 * join方法可以用于临时加入线程,一个线程在运算过程中,如果满足于条件,
 * 我们可以临时加入一个线程,让这个线程运算完,另外一个线程再继续运行。
 * @author leo-zeng
 *
 */
public class JoinTest {
	public static void main(String[] args) throws Exception {
		ThreadTest test  =new ThreadTest();
		ThreadTest test2  =new ThreadTest();
		test.setName("one");
		test2.setName("two");
		Thread t1 = new Thread(test);
		Thread t2 = new Thread(test2);
		t1.start();
		/**
		 * 主线程向下转时,碰到了t1.join(),t1要申请加入到运行中来,就是要CPU执行权。
		 * 这时候CPU执行权在主线程手里,主线程就把CPU执行权给放开,陷入冻结状态。
		 * 活着的只有t1了,只有当t1拿着执行权把这些数据都打印完了,主线程才恢复到运行中来
		 */
		//join 方法 确保 t1执行之后 执行t2
		t1.join();
		t2.start();
		
	}
}
class ThreadTest implements Runnable{
	
	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
				System.out.println(this.getName()+"------"+i);
		}
	}
	
}
运行结果:

one------0
one------1
one------2
one------3
one------4
two------0
two------1
two------2
two------3
two------4

主线程向下转时,碰到了t1.join(),t1要申请加入到运行中来,就是要CPU执行权。这时候CPU执行权在主线程手里,主线程就把CPU执行权给放开,陷入冻结状态。 活着的只有t1了,只有当t1拿着执行权把这些数据都打印完了,主线程才恢复到运行中来;这就是调用join方法的用法。

2.看下sleep、yield方法:

Thread.yield()方法暂停当前正在执行的线程对象,并执行其他线程。也就是交出CPU一段时间(其他同样的优先级或者更高优先级的线程可以获取到运行的机会);不会释放锁资源。

而Thread.sleep()方法使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行, 同时sleep函数不会释放锁资源;sleep可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会。

这两个的区别在于yield只能是同级,或者高级优先执行,而sleep可以低级,同级都可以有优先执行机会。

看以下两个demo

public class YieldTest {
	
	public static void main(String[] args) {
		ThreadTest2 test1 = new ThreadTest2();
		test1.setName("one");
		ThreadTest2 test2 = new ThreadTest2();
		test2.setName("two");
		Thread t1 =new Thread(test1);
		Thread t2 =new Thread(test2);
		t1.setPriority(Thread.MAX_PRIORITY);
		t2.setPriority(Thread.MIN_PRIORITY);
		t1.start();
		t2.start();		
	}
}
class ThreadTest2 implements Runnable{
	
	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	
	@Override
	public void run() {
		
		for (int i = 0; i <10; i++) {
			Thread.yield();
			System.out.println(this.getName()+"------"+i);
		};
		
	}
	
}
如果不用yield()方法的话,两个线程应该是交替进行的,用了yield()之后,cpu会多交出一些时间给ti优先执行。

 */
public class SleepTest {
	public static void main(String[] args) {
		ThreadTest3 test2 = new ThreadTest3();
		ThreadTest3 test3 = new ThreadTest3();
		Thread t1 =new Thread(test2);
		Thread t2 =new Thread(test3);
			t1.setPriority(Thread.MAX_PRIORITY);//设置最高级别
			t2.setPriority(Thread.MIN_PRIORITY);//设置最低级别
			t1.start();
			t2.start();		
	}
}

class ThreadTest3 implements Runnable{

	@Override
	public void run() {
		
		for (int i = 0; i <10; i++) {
			try {
				Thread.sleep(100);
				System.out.println(Thread.currentThread().getName()+"------"+i);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			
		};
		
	}
}
使用sleep的话,随机性就大一些。

3.wait(),notify()方法

顺便说下Object 类的wait()方法和notify()方法,注意这个不是Thread类的方法;还有这两个方法主要是操作锁标志的,所以只能在synchronized方法或者synchronized block中

使用;wait()方法在睡眠的时候会放开锁,给其他的线程使用。wait()有两种方式获得锁:1.wait(longtimeout),通过设定时间来获得锁,值得注意的是,timeout这个时间到了以后,它不会立即醒来,而是要看那个正在使用这把锁的线程是否结束。2.通过notify()的方法,通知需要这把锁的wait(),使之唤醒,还有wait 方法也要和sleep方法区别,上面说到sleep方法是不释放锁资源的。

<think>好的,我现在需要帮助用户了解Python中的thread.join()方法。首先,我得回忆一下自己对这个方法的理解。join()方法用于线程同步,让主线程等待子线程完成后再继续执行。这是多线程编程中常用的一个机制,避免主线程提前结束导致子线程被意外终止。 接下来,我需要查阅用户提供的引用资料,确保回答准确。引用[4]里有一个示例代码,展示了如何使用thread.join(),看起来主线程在调用join()后会等待子线程完成。引用[5]提到join()在线程和进程中的异同,这里主要关注线程部分。引用[2]和[3]则详细解释了join()的原理和使用方法,比如阻塞主线程直到线程结束。 用户可能需要具体的示例来理解join()的作用。比如,当不使用join()时,主线程可能先于子线程结束,导致输出结果不完整或不正确。而使用join()后,主线程会等待,确保所有子线程执行完毕。这可以通过对比两段代码来展示效果,如引用[4]中的例子,在不调用join()时,val的值可能没有完全累加,而调用了join()后结果正确。 另外,需要说明join()的参数,比如timeout,设置超时时间后,主线程最多等待指定时间,超过后继续执行。这个在引用[3]或[5]中可能有提到,需要确认。 还要注意,多个线程调用join()的顺序,主线程会依次等待每个线程完成。比如先join(thread1)再join(thread2),或者反过来,这会影响线程的执行顺序吗?根据资料,join()只是等待,并不影响线程的启动顺序,线程还是并行执行的,但主线程会按调用join的顺序等待。 可能用户会遇到的常见问题包括:忘记调用join()导致程序提前退出,或者错误地认为join()会影响线程的执行顺序。需要澄清这些误解,强调join()的作用仅是同步,并不控制线程的执行顺序,后者由操作系统调度决定。 最后,整理这些信息,分步骤说明join()用法,提供示例代码,并对比使用和不使用join()的结果差异。同时,总结注意事项和常见问题,帮助用户全面理解。</think>### Python thread.join() 方法使用说明 #### 1. 核心作用 `thread.join()` 用于阻塞**当前线程**(通常是主线程),直到目标线程执行结束[^5]。例如: ```python import threading def task(): print("子线程开始执行") # ... 执行具体操作 thread = threading.Thread(target=task) thread.start() thread.join() # 主线程在此处等待子线程结束 print("主线程继续执行") ``` #### 2. 基础语法 ```python thread.join(timeout=None) ``` - `timeout`:最长等待时间(秒),超时后继续执行当前线程[^3] #### 3. 典型应用场景 **(1) 确保线程顺序执行** ```python def worker(num): print(f"线程{num}开始工作") threads = [] for i in range(3): t = threading.Thread(target=worker, args=(i,)) threads.append(t) t.start() for t in threads: t.join() # 等待所有线程完成 print("所有线程执行完毕") ``` **(2) 资源同步控制** 引用[4]的数值累加示例: ```python val = 0 def increment(): global val for _ in range(1000): val +=1 t1 = threading.Thread(target=increment) t2 = threading.Thread(target=increment) t1.start() t2.start() t1.join() # 必须等待子线程完成 t2.join() print(val) # 正确输出2000 ``` 若不使用`join()`,可能得到不正确结果(因主线程提前输出未完成的计算) #### 4. 关键特性对比 | 场景 | 不使用join() | 使用join() | |---------------------|---------------------------|----------------------------| | 主线程执行顺序 | 立即继续执行 | 等待目标线程结束 | | 资源竞争 | 可能出现数据不同步 | 确保操作完成 | | 程序终止时机 | 主线程结束即终止程序 | 等待所有线程正常结束 | #### 5. 使用注意事项 1. **调用顺序**:必须在`thread.start()`之后调用 2. **超时控制**:`timeout`参数可实现非永久等待 3. **多个线程**:对多个线程依次调用`join()`会形成顺序等待 4. **守护线程**:守护线程(daemon=True)会被强制终止,join()对其无效[^2] #### 6. 常见误区 **错误理解**:认为`join()`会启动线程 **正确认知**:线程必须通过`start()`启动,join()仅用于同步
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值