Java多线程编程-Thread API
我们都知道在执行多线程的时候,我们调用start方法的时候,线程不会立即执行,因为需要获得CPU的执行权之后才能运行线程。但是我们也可以让执行的线程放弃CPU的执行权。
Thread.yield()方法
yield():给调度程序的提示是当前线程愿意放弃当前使用的处理器。调度程序可以随意忽略此提示
Yield是一种启发式尝试,旨在提高线程之间的相对进程,否则将过度利用CPU。它的使用应与详细的性能分析和基准测试结合使用,以确保它确实具有所需的效果
很少适合使用此方法。它可能对调试或测试有用,因为它可能有助于重现由于竞争条件而产生的错误。当设计诸如java.util.concurrent.locks包中的并发控制结构时,它也可能很有用
源码:
public static native void yield();
我们先调用这个方法:
public class ThreadYieldV1 extends Thread {
@Override
public void run() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
System.out.println("current i value:" + i);
}
long endTime = System.currentTimeMillis();
System.out.println("use total time:" + (endTime - startTime));
}
}
运行代码:
public class ThreadYieldV1Main {
public static void main(String[] args) {
ThreadYieldV1 threadYieldV1 = new ThreadYieldV1();
threadYieldV1.start();
}
}
运行结果:
总共运行时间为450ms,当我们调用yield方法,让到暂时放弃CPU的执行权,看看时间。yield放弃之后有可能会立即获得,这个是不确定的。
public class ThreadYieldV1 extends Thread {
@Override
public void run() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
Thread.yield();
System.out.println("current i value:" + i);
}
long endTime = System.currentTimeMillis();
System.out.println("use total time:" + (endTime - startTime));
}
}
运行结果:
调用yield方法让出CPU的执行权,所以时间会有有所增加。
守护进程
在Java中有两种线程,一种是用户线程,一种是守护线程
守护线程是一种特殊的线程,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程为垃圾回收线程。当进程中没有非守护线程,则垃圾回收线程就没有必要存在了,自动销毁。
声明为守护线程,使用setDaemon
Thread.setDaemon()方法
setDaemon():将此线程标记为isDaemon守护程序线程或用户线程。当所有正在运行的线程都是守护程序线程时,Java虚拟机将退出。
必须在线程启动之前调用此方法。
源码:
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
如果我们在线程start之后调用setDaemon方法会抛出异常:
线程还会继续运行
我们将代码改变一下:
public class ThreadDaemonV1Main {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
int i = 0;
while (true) {
i++;
System.out.println("current i value:" + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.setDaemon(true);
thread.start();
Thread.sleep(5000);
System.out.println("end");
}
}
运行结果:
为什么会停止呢?因为我们将thread 设置为了守护进程,但是主线程main线程已经运行完了。将没有这个主线程了(也就没有了非守护进程),所以会将守护线程自动销毁,所以会销毁thread守护线程。
Thread.setPriority()
我们知道多线程情况下,线程的运行是随机的,而不是有序的。但是我们可以对线程进行划分优先级,优先级较高的线程得到的CPU资源较多,可以帮助实现线程的执行顺序,判断哪一个线程有限执行。
setPriority():更改此线程的优先级。
首先,不带任何参数调用此线程的 checkAccess方法。这可能导致抛出SecurityException。否则,此线程的优先级将设置为指定的 newPriority 和该线程的线程组的最大允许优先级中的较小者。
源码:
public final static int MAX_PRIORITY = 10;
public final static int MIN_PRIORITY = 1;
/**
* 分配给线程的默认优先级
*/
public final static int NORM_PRIORITY = 5;
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);
}
}
我们看看init方法中的一段代码:
说明线程的优先级默认是取父级的线程优先级。我们创建两个线程测试一下:
public class ThreadPriorityV102 extends Thread {
@Override
public void run() {
System.out.println("02:" + this.getPriority());
}
}
第二个线程:
public class ThreadPriorityV101 extends Thread {
@Override
public void run() {
System.out.println("01:" + this.getPriority());
ThreadPriorityV102 threadPriorityV102 = new ThreadPriorityV102();
threadPriorityV102.start();
}
}
运行代码:
public class ThreadPriorityV1Main {
public static void main(String[] args) {
System.out.println("main thread priority:" + Thread.currentThread().getPriority());
ThreadPriorityV101 threadPriorityV101 = new ThreadPriorityV101();
threadPriorityV101.start();
}
}
运行结果:
从运行来开,这里的线程优先级都是默认的,默认取的是parent的优先级。
Main线程的优先级为最上层的,优先级为默认的5,main线程的子线程(ThreadPriorityV101 )没有设置,默认取父级的优先级,这里就是取main线程的优先级,ThreadPriorityV101 的子线程(ThreadPriorityV102 )也没有设置优先级,所以也是取ThreadPriorityV101 的优先级,所以都为5
所以由上的结论为如果没有设置线程优先级,这里取父节点的优先级,有优先级继承关系。
我们将设置线程ThreadPriorityV101 的优先级,ThreadPriorityV102 的优先级会和ThreadPriorityV101 一致
public class ThreadPriorityV1Main {
public static void main(String[] args) {
System.out.println("main thread priority:" + Thread.currentThread().getPriority());
ThreadPriorityV101 threadPriorityV101 = new ThreadPriorityV101();
threadPriorityV101.setPriority(8); //设置ThreadPriorityV101的优先级
threadPriorityV101.start();
}
}
运行结果:
由此结论是正确的。
我们进行进一步优先级设置高的会执行,并不是说优先级的搞的先执行玩。我们说了线程的执行顺序是随机的,设置优先级只是说明哪一个先执行。并不是说设置高的优先级的线程会先执行完。
线程1:
public class ThreadPriorityV201 extends Thread {
@Override
public void run() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 20000; j++) {
Random random = new Random();
random.nextInt();
j++;
}
}
long endTime = System.currentTimeMillis();
System.out.print("thread1 run total time:" + (endTime - startTime));
}
}
线程2:
public class ThreadPriorityV202 extends Thread {
@Override
public void run() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 20000; j++) {
Random random = new Random();
random.nextInt();
j++;
}
}
long endTime = System.currentTimeMillis();
System.out.println("thread2 run total time:" + (endTime - startTime));
}
}
运行代码:
public class ThreadPriorityV2Main {
public static void main(String[] args) {
ThreadPriorityV201 threadPriorityV201 = new ThreadPriorityV201();
threadPriorityV201.setPriority(Thread.MAX_PRIORITY); //设置为最大的优先级
threadPriorityV201.start();
ThreadPriorityV202 threadPriorityV202 = new ThreadPriorityV202();
threadPriorityV202.setPriority(Thread.MIN_PRIORITY); //设置为最小的优先级
threadPriorityV202.start();
}
}
运行结果:
可以多运行几次,大部分是线程ThreadPriorityV201 先运行完,但是也会出现上面的结果。