线程优先级的取值
Java线程的优先级是一个整数,其取值范围是1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
Thread源代码里对NORM_PRIORITY (数值为5) 的注释是“线程默认的优先级”。其实不然。默认的优先级是父线程的优先级。
设置优先级
可以通过setPriority方法(final的,不能被子类重载)更改优先级。优先级不能超出1-10的取值范围,否则抛出IllegalArgumentException。另外如果该线程已经属于一个线程组(ThreadGroup),该线程的优先级不能超过该线程组的优先级:
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
线程组的最大优先级
我们可以设定线程组的最大优先级,当创建属于该线程组的线程时该线程的优先级不能超过这个数。
线程组最大优先级的设定:
系统线程组的最大优先级默认为Thread.MAX_PRIORITY
创建线程组的时候其最大优先级默认为父线程组(如果未指定父线程组,则其父线程组默认为当前线程所属线程组)的最大优先级
可以通过setMaxPriority更改最大优先级,但无法超过父线程组的最大优先级
setMaxPriority的问题:
该方法只能更改本线程组及其子线程组(递归)的最大优先级。
但不能影响已经创建的直接或间接属于该线程组的线程的优先级,也就是说,即使目前有一个子线程的优先级比新设定的线程组优先级大,也不会更改该子线程的优先级。只有当试图改变子线程的优先级或者创建新的子线程的时候,线程组的最大优先级才起作用。
线程休眠
sleep() 定义在Thread.java中。
sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行。
class MyThead implements Runnable
{
public void run()
{
System.out.println("我休息了!");
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
System.out.println("一秒后在叫我吧!");
}
}
public class TheadMain
{
public static void main(String[] args)
{
MyThead myThead = new MyThead();
Thread thread = new Thread(myThead);
thread.start();
}
}
sleep()与wait()的比较
我们知道,wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态”。但是,wait()会释放对象的同步锁,而sleep()则不会释放锁。
public class ThreadB extends Thread{
private static Object obj = new Object();
public ThreadB(String name){
super(name);
}
public void run(){
synchronized(obj){
try {
for(int i=0; i <10; i++){
System.out.printf("%s: %d\n", this.getName(), i);
// i能被4整除时,休眠100毫秒
if (i%4 == 0)
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SleepLockTest {
public static void main(String[] args){
ThreadB t1 = new ThreadB("t1");
ThreadB t2 = new ThreadB("t2");
t1.start();
t2.start();
}
}
线程让步yield()方法
yield()方法可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程从运行状态转入就绪状态。
只是让当前的线程暂停一下,让系统的线程调度器重新调度一次。
很有可能,当某个线程调用了yield()方法暂停之后进入就绪状态,它又马上抢占了CPU的执行权,继续执行。
注意:
实际上,当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会。
class YieldThread implements Runnable{
public void run() {
for(int i=0;i<100;i++){
if(i==20){
//当i==20的时候,使用yield方法使当前线程让步
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"===="+i);
}
};
}
public class Demo03 {
public static void main(String[] args) {
YieldThread yt=new YieldThread();
Thread t1=new Thread(yt,"高级");
t1.setPriority(Thread.MAX_PRIORITY); //将t1线程设置成最高优先级
Thread t2=new Thread(yt,"低级");
t2.setPriority(Thread.MIN_PRIORITY); //将t2线程设置成最低优先级
t2.start();
t1.start();
}
}
sleep和yield的区别
1.sleep()方法暂停当前线程后,会给其他线程执行机会,线程优先级对此没有影响。
yield()方法会给优先级相同或更高的线程更高的执行机会。
2.sleep()方法会将线程转入阻塞状态,直到阻塞时间结束,才会转入就绪状态。
yield()方法会将当前线程直接转入就绪状态。
3.sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法时要么捕捉该异常,要么显示声明抛出该异常。
yield()方法则没有声明抛出任何异常。
4.sleep()方法比yield()方法有更好的移植性,通常不建议使用yield()方法来控制并发线程的执行。
设置线程的优先级
Thread了提供了以下两个优先级相关方法:
1.setPriority( int newPriority ) :设置线程的优先级
2.getPriority( ):获取线程的优先级
默认情况下,main主线程默认为NORM_PRIORITY普通优先级,其值为5。
线程插队之join方法
join方法:一个线程A插队到一个线程B之前,线程A阻塞
返回值类型 | 方法 | 解释 |
---|---|---|
void | join() | 等待该线程终止。 |
void | join(long millis) | 等待该线程终止的时间最长为 millis 毫秒 |
void | join(long millis, int nanos) | 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒 |
线程A:
public class ThreadA extends Thread{ private ThreadB tb; public void setTb(ThreadB tb){ this.tb = tb; } @Override public void run() { for( int i = 0 ; i < 100 ; i++ ){ System.out.println("ThreadA------------"+i); try { //线程tb使用join方法,插队到线程ta之前 //无参数的join方法,使用时是等到插队线程(tb)执行完成之后,才能执行被插队的线程(ta) //带参数的join方法,使用时是等到插队线程(tb)的插队时间完成之后,去执行被插队的线程(ta) tb.join(1); } catch (InterruptedException e) { e.printStackTrace(); } } } }
线程B:
public class ThreadB extends Thread{ public void run() { for( int i = 0 ; i < 100 ; i++ ){ System.out.println("ThreadB----"+i); } } }
测试:
import com.thread.join.ThreadA; import com.thread.join.ThreadB; public class TestJoin { public static void main(String[] args)
{ ThreadA ta = new ThreadA(); ta.start(); ThreadB tb = new ThreadB(); tb.start(); ta.setTb(tb); } }