sleep使当前线程睡眠指定的毫秒数(暂停执行),但由于系统计时器和调度方法的影响,时间不是那么精准。当线程在同步代码中持有monitor时,sleep不会导致线程释放已经获取的锁(虽然当前线程暂停了,但其他竞争线程依然无法获取锁)。会抛出线程中断异常,必须处理。到达指定之间之后,线程会自动苏醒,变为可运行状态而不是运行状态,所以sleep内的时间是线程休眠的最短时间。
sleep的重载函数,暂停线程精确到纳秒,其实内部还是以毫秒进行处理。
源码:
//sleep 重载函数
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
public class Demo7 {
public static void main(String[] args) {
System.out.println("slee before: "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("slee afeter: "+System.currentTimeMillis());
}
}
result:
slee before: 1565664285270
slee afeter: 1565664288271
join的用法是在一个线程A中调用另一个线程B的join,线程A在线程B执行完之前会一直阻塞在join方法的位置,这样就可以控制线程的执行顺序。
public class Demo7 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1 sleep 之前 "+System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1 sleep 之后"+System.currentTimeMillis());
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程2,join之前 "+System.currentTimeMillis());
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2,join之后 "+System.currentTimeMillis());
}
});
thread1.start();
thread2.start();
}
}
//运行结果,线程2的join之后这句话一定在线程1执行完之后。
线程1 sleep 之前 1565664869820
线程2,join之前 1565664869820
线程1 sleep 之后1565664870821
线程2,join之后 1565664870821
线程2,join之前 1565664952598
线程1 sleep 之前 1565664952598
线程1 sleep 之后1565664953599
线程2,join之后 1565664953599
join的重载函数
等待millis毫秒后,如果等待的线程依然没有执行完,就唤醒当前等待线程。
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1 sleep 之前 "+System.currentTimeMillis());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1 sleep 之后"+System.currentTimeMillis());
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程2,join之前 "+System.currentTimeMillis());
try {
thread1.join(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2,join之后 "+System.currentTimeMillis());
}
});
thread1.start();
thread2.start();
实现原理,内部利用wait实现:
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
yield线程让步,线程调用了yield后,当前线程由“运行状态”进入到“就绪状态”,从而让自己或者其他线程获取执行权;但并不能保证其它线程一定能获得执行权;也有可能当前线程继续运行!(让出的是下一个时间片)
public class Demo7 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
int count =1000;
while (count > 0) {
count = count -1;
}
System.out.println("线程1 "+System.currentTimeMillis());
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
int count =1000;
while (count > 0) {
count = count -1;
}
System.out.println("线程2 "+System.currentTimeMillis());
}
});
thread1.start();
thread2.start();
thread1.yield();
}
}
结果显示,线程1和线程2谁先执行的情况都有发生。
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
thread1.yield();
添加了优先级之后依然 两种情况都存在。
Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.
java中每个线程都有一个优先级,开发者可以改变优先级,必须在执行之前设置优先级,优先级高的线程比优先级低的更易于被执行。 Java 虚拟机和下层的操作系统之间的约定是操作系统必须选择有最高优先权的 Java 线程运行。一个高优先级的线程到来时,无论低优先级的线程是否在运行,都会中断(抢占)它。但操作系统有时可能会选择一个更低优先级的线程运行,所以高优先级线程不一定优先执行,最终由由调度程序决定哪一个线程被执行。
当线程的优先级没有指定时,所有线程都携带普通优先级,其中10 表示最高优先级,1 表示最低优先级,5 是普通优先级, MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY 。
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1 "+System.currentTimeMillis());
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程2 "+System.currentTimeMillis());
}
});
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.start();
thread1.start();
}
运行结果,各种情况都存在。
在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemon Thread)。
守护线程指当程序运行时在后台提供服务的线程,不是程序中不可获取的部分,守护线程起到辅助作用,没有它也可以,有了它可以为线程提供帮助,它提供的帮助你也可以不管(类似GC,文档的拼写检查)。守护线程为用户线程提供服务,当所有的非守护线程结束时,程序也就终止了虚拟机也就退出了。典型守护线程,垃圾收集器(GC)。
通过调用Thread对象的setDaemon(true)方法来设置守护线程(必须在线程start之前),不要再守护线程中做有关业务的逻辑操作(读取文件,数据库),因为守护线程可能随时发出中断,即使在程序执行过程中(用户线程执行完毕,VM会终止,此时可能守护线程还没执行完)。
public class Demo7 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1 "+System.currentTimeMillis());
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2 "+System.currentTimeMillis());
}
});
thread2.setDaemon(true);
thread2.start();
thread1.start();
}
}
线程2中syste.out的语句不会执行。