java中有三种创建线程的方式:
实现 Runnable 接口;
实现 Callable 接口;
继承 Thread 类。
实现 Runnable 和 Callable 接口的类其实是可以在线程中运行的任务,最后需要通过 Thread 来调用该任务实现线程新建。
实现 Runnable 接口 需要实现 run() 方法。
通过 Thread 调用 start() 方法来启动线程。如下所示:
//线程新建与启动
public static void main(String[] args) {
TheRunnable instance = new TheRunnable();
Thread thread = new Thread(instance);
thread.start();//线程启动
}
public class TheRunnable implements Runnable {
public void run() {
// do something
}
}
Callable 接口可以有返回值,而返回值通过FutureTask 进行封装,而Runnable接口无返回值。
示例:
//启动线程并返回结果,结果为1
public static void main(String[] args) throws ExecutionException, InterruptedException {
TheCallable tc = new TheCallable();
FutureTask future = new FutureTask(tc);
Thread thread = new Thread(future);
thread.start();
}
public class TheCallable implements Callable {
public Integer call() {
return "1";
}
}
继承 Thread 类的方式,也需要实现 run() 方法,Thread 类也实现了 Runable 接口。
当程序调用 start() 方法启动一个线程时,虚拟机会将该线程放入就绪队列中等待被调度,当一个线程被调度时会执行该线程的 run() 方法。
如下所示:
public class TheThread extends Thread {
public void run() {
// do Something
}
}
public static void main(String[] args) {
TheThread tt = new TheThread();
tt.start();
}
守护进程:
使用 setDaemon() 方法将一个线程设置为守护线程。
public static void main(String[] args) {
Thread thread = new Thread(new TheRunnable());
thread.setDaemon(true);//设置守护进程
}
线程休眠:
Thread类的sleep()静态方法。Thread.sleep(millisec) 方法会休眠当前正在执行的线程,在此过程中,本线程不让出执行权或锁,millisec 单位为毫秒。
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
线程让出
Thread类的静态方法yield()。
Thread.yield() ,让出当前线程的cpu所有权,让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程过去运行机会,该方法只是对线程调度器的一个建议并非强制。
public void run() {
Thread.yield();
}
线程中断
interrupt()方法
它不是中断某个线程,只是给线程发送一个中断信号,让线程在无限等待时,阻塞、限期等待时能抛出InterruptedException异常从而结束线程,如果某个线程要能够中断,那么需要程序中有抛出这个异常,否则这个线程还是不会中断的。
如下示例:
private static class TheThread extends Thread {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
会在sleep时中断并退出线程。
另外调用 interrupt() 方法会设置线程的中断标记,可以在线程代码的run()方法中调用 interrupted() 方法判断,返回 true则可以提前结束线程。
线程协同
join(): 等待线程终止。
join是Thread类的一个方法,启动线程后直接调用,即join()的作用是:“等待该线程终止再执行后面的操作”,一般是指的主线程等待子线程的终止。也就是在子线程调用了join()方法之后的代码,等到子线程结束了才能执行。
public static void main(String[] args) {
Thread th=new ThreadA("1");
th.start();
try {
th.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class ThreadA extends Thread{
public void run() {
for (int i = 0; i
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
主线程运行开始
子线程运行开始
子线程运行 : 0
子线程运行 : 1
子线程运行 : 2
子线程运行 : 3
子线程运行 : 4
子线程运行 : 5
子线程运行 : 6
子线程运行 :7
子线程运行 : 8
子线程运行 : 9
子线程运行结束
主线程运行开始
守护进程:
setDaemon(): 设置一个线程为守护线程。
守护进程:当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当JVM中最后一个用户线程结束时,守护线程才会随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器)
守护进程的子进程也是守护进程。
线程等待:
Object类的wait()方法:
让线程等待,让出本对象的锁,等待指定时间(传入超时时间参数)或无限期等待。等待指定时间后自动进入可执行状态,无限期等待则需要其他进程通知。
wait方法必须在synchronized块或方法中,执行后线程进入对象对应的等待池中。
线程通知:
notify()/notifyall(): 通知一个线程(或所有线程)继续运行。
本方法必须在synchronized块或方法中,执行后线程不会马上让出锁,而是继续执行完成。
线程状态变迁图如下:
图片摘自《Java多线程编程核心技术》
领取专属 10元无门槛券
私享最新 技术干货