多线程中有许多常见的方法能够使多线程的使用过程中实现更多的动能,比如Thread类提供的sleep()、yield()、join()等方法。
1.sleep()
sleep()是使线程暂停执行一段时间的方法,是Thread类的静态方法,是线程用来控制自身流程的,暂停过程中会把执行机会让给其它线程,等到计时时间一到,此线程会自动"苏醒"。sleep()方法必须捕获异常,在sleep的过程中,有可能被被其它对象调用它的interrupt(),产生InterruptedException异常。sleep()的弊端就是不会释放"锁标志",不存在线程间的通信,因此容发生死锁,因此不推荐使用sleep()方法来暂停。示例代码如下:
package person;
public class Student {
public int k=0;
public int total;
public int perMonth;
public String name;
public void saveMoney(Student s) {
// TODO Auto-generated method stub
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
s.k+=1;
if(s.k>=12)
System.out.println(s.name+"存储结束,总共存储了:"+s.total+"元");
else
{
s.total=s.total+s.perMonth;
System.out.println(s.name+"第"+k+"月总共拥有"+s.total+"元");
}
}
}
2.setPriority(int value)
该方法主要用来设置线程的优先级,value值取值范围从1-10,值越大则表明线程越重要。本文示例使用Thread.MAX_PRIORITY和Thread.MIN_PRIORITY。
package waytobuildthread;
import person.Student;
public class RunnableTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student tom=new Student();
Student jack=new Student();
tom.total=1000;
tom.perMonth=200;
tom.name="Tom";
jack.total=1500;
jack.perMonth=100;
jack.name="Jack";
Thread t1=new Thread(new ImplementRunnable(tom));
t1.setPriority(Thread.MAX_PRIORITY);
Thread t2=new Thread(new ImplementRunnable(jack));;
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
运行程序,结果如下:
Tom第1月总共拥有1200元
Tom第2月总共拥有1400元
Jack第1月总共拥有1600元
Jack第2月总共拥有1700元
Jack第3月总共拥有1800元
Tom第3月总共拥有1600元
Tom第4月总共拥有1800元
Tom第5月总共拥有2000元
Jack第4月总共拥有1900元
Jack第5月总共拥有2000元
Jack第6月总共拥有2100元
Tom第6月总共拥有2200元
Jack第7月总共拥有2200元
Jack第8月总共拥有2300元
Tom第7月总共拥有2400元
Jack第9月总共拥有2400元
Jack第10月总共拥有2500元
Jack第11月总共拥有2600元
Tom第8月总共拥有2600元
Tom第9月总共拥有2800元
Tom第10月总共拥有3000元
Tom第11月总共拥有3200元
Tom存储结束,总共存储了:3200元
Jack存储结束,总共存储了:2600元
从上面结果看出,Tom的优先级高,所以他每个月先办业务的可能性大。
3.join()
使用join()方法即将该线程加入到当前线程中,即主线程,也就是main()方法的执行区域。如果将某个线程调用该方法,则会将该线程加入到主线程,那么当执行该线程时,只有当该线程执行结束之后,才会往下执行。同时该方法也需要捕获异常。
package waytobuildthread;
import person.Student;
public class RunnableTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student tom=new Student();
Student jack=new Student();
tom.total=1000;
tom.perMonth=200;
tom.name="Tom";
jack.total=1500;
jack.perMonth=100;
jack.name="Jack";
Thread t1=new Thread(new ImplementRunnable(tom));
t1.start();
try {
//t1线程加入到main线程中来,只有t1线程运行结束,才会继续往下走
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread t2=new Thread(new ImplementRunnable(jack));;
t2.start();
}
}
运行结果如下:
Tom第1月总共拥有1200元
Tom第2月总共拥有1400元
Tom第3月总共拥有1600元
Tom第4月总共拥有1800元
Tom第5月总共拥有2000元
Tom第6月总共拥有2200元
Tom第7月总共拥有2400元
Tom第8月总共拥有2600元
Tom第9月总共拥有2800元
Tom第10月总共拥有3000元
Tom第11月总共拥有3200元
Tom存储结束,总共存储了:3200元
Jack第1月总共拥有1600元
Jack第2月总共拥有1700元
Jack第3月总共拥有1800元
Jack第4月总共拥有1900元
Jack第5月总共拥有2000元
Jack第6月总共拥有2100元
Jack第7月总共拥有2200元
Jack第8月总共拥有2300元
Jack第9月总共拥有2400元
Jack第10月总共拥有2500元
Jack第11月总共拥有2600元
Jack存储结束,总共存储了:2600元
同时,join(time)还能跟时间值,表示最多等多少时间,如果超过时间即使该线程还没结束,也要往下执行线程。
package waytobuildthread;
import person.Student;
public class RunnableTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student tom=new Student();
Student jack=new Student();
tom.total=1000;
tom.perMonth=200;
tom.name="Tom";
jack.total=1500;
jack.perMonth=100;
jack.name="Jack";
Thread t1=new Thread(new ImplementRunnable(tom));
t1.start();
try {
//t1线程加入到main线程中来,只有t1线程运行结束,才会继续往下走
t1.join(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread t2=new Thread(new ImplementRunnable(jack));;
t2.start();
}
}
运行程序,得到如下结果:
Tom第1月总共拥有1200元
Tom第2月总共拥有1400元
Jack第1月总共拥有1600元
Tom第3月总共拥有1600元
Jack第2月总共拥有1700元
Tom第4月总共拥有1800元
Jack第3月总共拥有1800元
Tom第5月总共拥有2000元
Jack第4月总共拥有1900元
Tom第6月总共拥有2200元
Jack第5月总共拥有2000元
Tom第7月总共拥有2400元
Jack第6月总共拥有2100元
Tom第8月总共拥有2600元
Jack第7月总共拥有2200元
Tom第9月总共拥有2800元
Jack第8月总共拥有2300元
Tom第10月总共拥有3000元
Jack第9月总共拥有2400元
Tom第11月总共拥有3200元
Tom存储结束,总共存储了:3200元
Jack第10月总共拥有2500元
Jack第11月总共拥有2600元
Jack存储结束,总共存储了:2600元
根据结果可以知道,Tom使用了join(2000),表示最多等待两秒,这两秒内Tom先执行,两秒结束就轮到Jack,而Jack执行一次之后又轮到Tom,Tom又有两秒时间,如此循环。
4.yield()
yield()方法表示临时暂停的意思,并且yield()和sleep()还是有些区别的,具体,请看如下:
package waytobuildthread;
import person.Student;
public class RunnableTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
final Student tom=new Student();
final Student jack=new Student();
tom.total=1000;
tom.perMonth=200;
tom.name="Tom";
jack.total=1500;
jack.perMonth=100;
jack.name="Jack";
Thread t1= new Thread(){
public void run(){
while(tom.k<12)
tom.saveMoney(tom);
}
};
t1.setPriority(Thread.MAX_PRIORITY);
Thread t2= new Thread(){
public void run(){
Thread.yield();
while(jack.k<12)
jack.saveMoney(jack);
}
};
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
运行结果如下:
Tom第1月总共拥有1200元
Jack第1月总共拥有1600元
Tom第2月总共拥有1400元
Jack第2月总共拥有1700元
Tom第3月总共拥有1600元
Tom第4月总共拥有1800元
Tom第5月总共拥有2000元
Tom第6月总共拥有2200元
Tom第7月总共拥有2400元
Jack第3月总共拥有1800元
Tom第8月总共拥有2600元
Jack第4月总共拥有1900元
Tom第9月总共拥有2800元
Jack第5月总共拥有2000元
Tom第10月总共拥有3000元
Jack第6月总共拥有2100元
Tom第11月总共拥有3200元
Jack第7月总共拥有2200元
Tom存储结束,总共存储了:3200元
Jack第8月总共拥有2300元
Jack第9月总共拥有2400元
Jack第10月总共拥有2500元
Jack第11月总共拥有2600元
Jack存储结束,总共存储了:2600元
sleep()和yield()都有表示暂停的意思,但是两者有很大区别的:
1.sleep()方法给其它线程运行机会时不考虑线程优先级,因此会给优先级低的线程以运行机会,而yield()只会给相同优先级或者更高优先级的线程运行机会。
2.线程执行sleep()方法后会进入阻塞状态,因此执行sleep()方法的线程在指定时间内肯定不会被执行,而执行yield()方法只是使当前线程重新回到可执行状态,所以执行yield()方法的线程有可能进入到可执行状态后马上又被执行。
3.sleep()方法需要捕获异常,而yield()方法不需要。
4.sleep()方法比yield()方法具有更好的移植性。