Task 1.1 Join
- 实验要求
- 实验关键代码
- 关键代码分析
- 实验测试代码
- 测试结果分析
实验要求
◆ Implement KThread.join();
◆ Note that another thread does not have to call join(), but if it is called, it must be called only onceThe result of calling join() a second time on the same thread is undefined, even if the second caller is a different thread than the first caller;
◆ A thread must finish executing normally whether or not it is joined;
实验关键代码
变量声明
private ThreadQueue waitForJoinQueue = null;//等待join方法结束的线程队列
private int JoinCount = 0;//定义调用join的次数
方法实现
关键方法主要为join()方法和finish()方法。
Join()方法:
public void join() {
Lib.debug(dbgThread, "Joining to thread: " + toString());
Lib.assertTrue(this != currentThread);
if(++JoinCount!=1){//如果调用超过一次,则调用失败
System.out.println("sorry,只能调用一次!");
return;
}
boolean preState = Machine.interrupt().disable();//关中断
//让this线程成为waitForJoinQueue队列的头,表明只有先执行this线程,才会去执行队列里的线程
waitForJoinQueue.acquire(this);
waitForJoinQueue.waitForAccess(currentThread);//将当前线程加入到waitForJoinQueue队列里
currentThread.sleep();//当前线程睡眠
Machine.interrupt().restore(preState);//恢复中断
}
Finish()方法中在线程sleep()之前添加的核心代码为:
KThread x = currentThread.waitForJoinQueue.nextThread();
if(x!=null) x.ready();
关键代码分析
思路分析
当前执行线程(如a线程)调用某线程(如b线程)的join()方法,结果要让a线程睡眠,而让b线程先于a线程执行,b线程执行结束a线程才可继续执行。
方法解释
1、join()方法
将a线程暂时保存到b线程的waitForJoinQueue队列中【在以上代码中采用waitForJoinQueue来保存】,然后让a线程睡眠。
2、finish()方法
在b线程执行结束时(线程结束时会调用finish()方法),扫描一下waitForJoinQueue,如果有线程,则将它唤醒。
关键点和难点
关键点:理清join()方法的含义,要想办法将睡眠的线程存起来,到唤醒时将其唤醒。
难点:理解finish()方法是每个线程执行结束时必会执行的方法。
实验测试代码
public static void joinSelfTest(){
final KThread a = new KThread(new PingTest(1));
System.out.println("thread 1 启动");
a.fork();
System.out.println("调用join方法,当前线程阻塞,thread 1 执行结束后thread 0 再执行【thread 0 为主线程】");
a.join();
System.out.println("thread 0 开始执行");
new PingTest(0).run();
}
测试结果分析
测试结果截图
测试结果分析
实验测试代码使用main线程【在测试结果中使用thread 0来表示】和a线程【在测试结果中用thread 1来表示】来对join()方法进行测试,main线程通过调用a线程的join()方法,从而让a线程先执行,执行结束后main线程再继续执行。