1. yield() 方法
使线程放弃当前的CPU资源(多个线程争抢CPU资源去执行,包括刚放弃的此线程)。但放弃的时间不确定,也有可能刚刚放弃,马上又抢到CPU资源运行。
public class MyThread extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
int count = 0;
for (int i = 0; i < 50000000; i++) {
Thread.yield();
count = count + (i + 1);
}
long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
}
}
public class Test {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
/*
运行结果:
(无yield)
用时:8毫秒!
(有yield)
用时:3166毫秒!
*/
}
将CPU资源让出导致运行时间变长
2. 线程优先级
在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是 CPU优先执行优先级较高的线程对象中的任务。
(1)设置线程的优先级使用 setPriority() 方法,源码如下:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
线程优先级分为1 ~10 这10个等级,超出范围则会抛出 IllegalArgumentException。JDK中使用3个常量来预置定义优先级的值:
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
(2)线程优先级具有继承特性
在Java中,线程优先级具有继承性,比如 A线程启动B线程,则B线程的优先级与A是一样的。
public class MyThread3 extends Thread {
@Override
public void run() {
System.out.println("MyThread3 run priority = " + this.getPriority());
}
}
public class MyThread2 extends Thread {
@Override
public void run() {
System.out.println("MyThread2 run priority = " + this.getPriority());
MyThread3 thread3 = new MyThread3();
thread3.start();
}
}
public class Test2 {
public static void main(String[] args) {
System.out.println("main thread begin priority = " + Thread.currentThread().getPriority());
//Thread.currentThread().setPriority(6);
System.out.println("main thread end priority = " + Thread.currentThread().getPriority());
MyThread2 thread2 = new MyThread2();
thread2.start();
}
/*
运行结果:
(无 setPriority(6))
main thread begin priority = 5
main thread end priority = 5
MyThread2 run priority = 5
MyThread3 run priority = 5
(有 setPriority(6))
main thread begin priority = 5
main thread end priority = 6
MyThread2 run priority = 6
MyThread3 run priority = 6
*/
}
(3)
优先级具有规则性
public class MyThread4 extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
long addResult = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 50000; j++) {
Random random = new Random();
random.nextInt();
addResult += i;
}
}
long endTime = System.currentTimeMillis();
System.out.println("****** thread4 use time = " + (endTime - beginTime));
}
}
public class MyThread5 extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
long addResult = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 50000; j++) {
Random random = new Random();
random.nextInt();
addResult += i;
}
}
long endTime = System.currentTimeMillis();
System.out.println("##### thread5 use time = " + (endTime - beginTime));
}
}
public class Test4 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
MyThread4 thread4 = new MyThread4();
thread4.setPriority(10);;
thread4.start();
MyThread5 thread5 = new MyThread5();
thread5.setPriority(1);;
thread5.start();
}
}
/*
运行结果:
****** thread4 use time = 194
****** thread4 use time = 238
****** thread4 use time = 238
****** thread4 use time = 313
****** thread4 use time = 325
##### thread5 use time = 339
##### thread5 use time = 370
##### thread5 use time = 371
##### thread5 use time = 389
##### thread5 use time = 391
----------------------------
****** thread4 use time = 122
****** thread4 use time = 161
****** thread4 use time = 166
##### thread5 use time = 161
##### thread5 use time = 236
##### thread5 use time = 286
****** thread4 use time = 226
****** thread4 use time = 260
##### thread5 use time = 256
##### thread5 use time = 228
------------------------------
****** thread4 use time = 130
****** thread4 use time = 149
##### thread5 use time = 151
****** thread4 use time = 100
****** thread4 use time = 192
****** thread4 use time = 166
##### thread5 use time = 204
##### thread5 use time = 202
##### thread5 use time = 231
##### thread5 use time = 332
*/
}
从结果中,高优先级的线程总是大部分先执行完,但不代表高优先级的线程全部先执行完。下面我们交换 thread4 和 thread5 的优先级,再试一下
public class Test4 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
MyThread4 thread4 = new MyThread4();
thread4.setPriority(1);;
thread4.start();
MyThread5 thread5 = new MyThread5();
thread5.setPriority(10);;
thread5.start();
}
}
/*
运行结果:
##### thread5 use time = 194
##### thread5 use time = 255
##### thread5 use time = 317
****** thread4 use time = 324
##### thread5 use time = 345
****** thread4 use time = 359
****** thread4 use time = 369
##### thread5 use time = 373
****** thread4 use time = 394
****** thread4 use time = 394
----------------------------
****** thread4 use time = 158
##### thread5 use time = 191
##### thread5 use time = 202
##### thread5 use time = 292
##### thread5 use time = 321
****** thread4 use time = 307
##### thread5 use time = 269
****** thread4 use time = 356
****** thread4 use time = 236
****** thread4 use time = 214
------------------------------
##### thread5 use time = 170
##### thread5 use time = 181
****** thread4 use time = 215
****** thread4 use time = 228
##### thread5 use time = 337
##### thread5 use time = 348
##### thread5 use time = 353
****** thread4 use time = 355
****** thread4 use time = 396
****** thread4 use time = 393
*/
}
可以发现,大部分 thread5 先执行完,说明
线程的优先级与代码执行顺序无关,线程的优先级具有一定的规则性,也就是 CPU 会优先将执行资源给优先级比较高的线程。
(4) 优先级具有随机性
上面代码说明:线程优先级较高则会被优先执行完 run() 方法中的任务,但是并不绝对。线程的优先级还具有“随机性”,优先级较高的线程不一定每次都能先执行完。
public class MyThread6 extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 1000; j++) {
Random random = new Random();
random.nextInt();
}
}
long endTime = System.currentTimeMillis();
System.out.println("****** thread6 use time = " + (endTime - beginTime));
}
}
public class MyThread7 extends Thread {
@Override
public void run() {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 1000; j++) {
Random random = new Random();
random.nextInt();
}
}
long endTime = System.currentTimeMillis();
System.out.println("##### thread7 use time = " + (endTime - beginTime));
}
}
public class Test6 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
MyThread6 thread6 = new MyThread6();
thread6.setPriority(5);;
thread6.start();
MyThread7 thread7 = new MyThread7();
thread7.setPriority(6);;
thread7.start();
}
}
/*
运行结果:
****** thread6 use time = 2
##### thread7 use time = 2
****** thread6 use time = 7
##### thread7 use time = 6
##### thread7 use time = 1
##### thread7 use time = 2
##### thread7 use time = 1
****** thread6 use time = 14
****** thread6 use time = 1
****** thread6 use time = 1
----------------------------
****** thread6 use time = 0
****** thread6 use time = 3
##### thread7 use time = 12
##### thread7 use time = 7
##### thread7 use time = 10
****** thread6 use time = 1
****** thread6 use time = 18
****** thread6 use time = 1
##### thread7 use time = 2
##### thread7 use time = 1
------------------------------
##### thread7 use time = 7
****** thread6 use time = 1
****** thread6 use time = 2
##### thread7 use time = 10
##### thread7 use time = 10
****** thread6 use time = 5
##### thread7 use time = 6
****** thread6 use time = 11
##### thread7 use time = 7
****** thread6 use time = 13
*/
}
为了结果体现“随机性”,所以两个线程的优先级一个设置为5,另一个设置为6。从这次的结果来看,并没有明显的规律,所以:
不要把线程的优先级与运行结果的顺序作
为衡量的标准,优先级较高的线程不一定每一次都先执行完 run() 方法中的任务。
3. 守护线程
Java中有两种线程,一种是用户线程,另一种就是守护(Daemon)线程。
什么是守护线程?守护线程是一种特殊的线程,他的特性有陪伴的含义,当进程中不存在非守护线程了,则守护线程自动销毁。守护线程的作用是为其他线程的运行提供便利服务,最典型的应用就是 GC(垃圾回收器)。
public class MyThread extends Thread {
private int i = 0;
@Override
public void run() {
try {
while (true) {
i++;
System.out.println("i = " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.setDaemon(true); //将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
thread.start();
Thread.sleep(5000);
System.out.println("我离开 thread 对象也不再打印了,也就是停止了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
运行结果:
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
我离开 thread 对象也不再打印了,也就是停止了
*/
}