一.线程的调度
1、调整线程优先级:Java线程有优先级,优先级高的线程会获得较多的运行机会。
Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:
static int MAX_PRIORITY
线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
分配给线程的默认优先级,取值为5。
Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。
二.上篇文章提到线程有五个状态,其中有一个阻塞状态,到底哪几种情况会导致线程阻塞呢?
先看一下这个图:
考虑一下三个方面,不考虑IO阻塞的情况:
睡眠;
等待;
因为需要一个对象的锁定而被阻塞。
这就涉及到线程常用的几个方法
1.睡眠(线程的静态方法)
Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)静态方法强制当前正在执行的线程休眠(暂停执行),使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
睡眠的位置:放在run()方法之内。
public class ThreadSleep implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i);
try {
//睡眠一秒
Thread.sleep(1000);//参数以毫秒计算
} catch (InterruptedException e) {
e.printStackTrace();
}
//每隔10个输出一个字符串
if(i%10==0){
System.out.println("-------"+i);
}
}
}
public static void main(String[] args) {
ThreadSleep ts=new ThreadSleep();
Thread thread=new Thread(ts);
thread.start();
}
}
输出结果:(省略一部分)
2、等待:
Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法,行为等价于调用 wait(0) 一样。
调用wait()和notify()系列方法时,当前线程必须拥有此对象监视器(即对象锁)。
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
此方法只应由作为此对象监视器的所有者的线程来调用。
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
此方法只应由作为此对象监视器的所有者的线程来调用。
3.让步(线程的静态方法)
Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
![](https://img-blog.csdn.net/20170313110210046?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSW1fU2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
再次运行一下:
![](https://img-blog.csdn.net/20170313110237640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSW1fU2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
可以看出来:(实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。)
public class ThreadYield extends Thread{
public ThreadYield(String name) {
super(name);
}
@SuppressWarnings("static-access")
@Override
public void run() {
for (int i = 0; i < 15; i++) {
System.out.println(this.getName()+"------"+i);
//当i为10时,线程就会把cpu时间让掉,让其他或者自己的线程执行
if(i==10){
this.yield();
}
}
}
public static void main(String[] args) {
ThreadYield ty1=new ThreadYield("小明");
ThreadYield ty2=new ThreadYield("小红");
ty1.start();
ty2.start();
}
}
运行一下:再次运行一下:
可以看出来:(实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。)
4、加入(线程的非静态方法)
join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
![](https://img-blog.csdn.net/20170313134937370?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSW1fU2h1YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
为什么结果没有变呢?这是因为main方法本身也是一个线程,当主线程main方法执行完毕时,线程t1有可能正在启动,或者还没能运行完,总之就是晚于主线程的执行。
这时候join()方法就可以控制运行的顺序。
public class ThreadJoin implements Runnable{
private static int count=5;
public static int getCount() {
return count;
}
public static void setCount(int count) {
ThreadJoin.count = count;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
count++;
}
}
public static void main(String[] args) {
ThreadJoin join1=new ThreadJoin();
Thread t1=new Thread(join1);
t1.start();
System.out.println(count);
}
}
运行一下:为什么结果没有变呢?这是因为main方法本身也是一个线程,当主线程main方法执行完毕时,线程t1有可能正在启动,或者还没能运行完,总之就是晚于主线程的执行。
这时候join()方法就可以控制运行的顺序。
public static void main(String[] args) {
ThreadJoin join1=new ThreadJoin();
Thread t1=new Thread(join1);
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
这时候结果就是10了。