什么是线程
并发与并行
java 中实现线程的方式
继承 Thread 类,实现 run() 方法
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("这是创新的新线程,"+Thread.currentThread().getName());
}
public static void main(String[] args) {
// 创建线程类
MyThread thread = new MyThread();
thread.start(); // 启动一个创建的线程
System.out.println("这是主线程 main,"+Thread.currentThread().getName());
}
}
实现 Runnable 接口
public class MyRunable implements Runnable{
@Override
public void run() {
System.out.println("这是创新的新线程,"+Thread.currentThread().getName());
}
public static void main(String[] args) {
Runnable runable = new MyRunable();
Thread t1 = new Thread(runable);
t1.start(); // 启动线程
Thread t2 = new Thread(runable);
t2.start(); // 启动线程
/**
* java 8 中 Runable 接口被标注为函数式接口,
* @FunctionaInterface 修饰,可
* 以使用 Lombok 表达式创建对象
*/
Runnable able = () -> {
System.out.println("使用 java 8 Lombok 表达式创建线程,"+Thread.currentThread().getName());
};
Thread t3 = new Thread(able);
t3.start(); // 启动线程
System.out.println("这是主线程 main,"+Thread.currentThread().getName());
}
}
通过 Callable 和 Future 接口创建线程
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// 休眠两秒
Thread.sleep(2000);
System.out.println("实现 Callable 接口 创建线程");
return "SUCCESS";
}
public static void main(String[] args) throws Exception {
Callable callable = new MyCallable();
/**
* java5 提供了 Future 接口来代表 Callable 接口里的 call() 方法的返回值
* 并为 Future 提供了一个 FutureTask 实现类,该类实现了 Future 接口,并
* 是实现了 Runnable 接口,所以 FutureTask 可以做为 Thread 类的 target
* 同时也解决了 Callable 对象不能作为 Thread 类的 target 这一问题
*/
FutureTask<String> task = new FutureTask<String>(callable);
Thread t1 = new Thread(task,"call");
t1.start();
// 获取返回值
String result = task.get();
System.out.println("返回值:"+result);
/**
* 使用 lambda 表达式创建
*/
FutureTask<Integer> task2 = new FutureTask<Integer>(() -> {
System.out.println("100 分");
return 100;
});
Thread t2 = new Thread(task2,"task2");
t2.start();
// Future 接口 get() 方法获取返回值 会阻塞线程,知道拿到返回值 其他线程才可以运行
Integer resu = task2.get();
System.out.println("返回值:"+resu);
// 使用线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
Callable<String> myCallable = new MyCallable();
// 返回 Future 实例
Future<String> submit = executorService.submit(myCallable);
// 获取返回值,会阻塞线程
String result3 = submit.get();
System.out.println(result3);
System.out.println("main 线程");
}
}
线程的生命周期
java 的线程状态 6 中
线程的启动
线程的终止
public class MyInterrupt implements Runnable {
private int i = 1;
@Override
public void run() {
/**
* Thread.currentThread().isInterrupted()
* 返回会一个中段标记,默认为 false
*/
while (!Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName()+"="+i++);
}
}
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new MyInterrupt();
Thread t1 = new Thread(runnable,"t1");
Thread t2 = new Thread(runnable,"t2");
t1.start(); // 启动线程
t2.start();
Thread.sleep(2000);
/**
* 设置中断标记 interrupt = true
* 他会在当前线程最有一次执行完后通过判断中断标记,结束线程的执行
*/
t1.interrupt();
}
}
上述代码的 t1.interrupt() 只会让 t1 线程中断,而 t2 线程不会
public class MyInterrupt2 implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
// 睡眠 200 秒
try {
TimeUnit.SECONDS.sleep(200);
} catch (InterruptedException e) {
/**
* InterruptedException 触发了线程的复位,线程不会终止即
* Thread.currentThread().isInterrupted() 返回 初始值 false
*/
e.printStackTrace();
// 有人触发中断通知,在这里做处理
// 继续中断,线程会停止
Thread.currentThread().interrupt();
}
}
/**
* 如果没有改变中段标记为 true
* 正常情况下是 200 秒之后才会执行
*/
System.out.println("processor end");
}
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new MyInterrupt2();
Thread t1 = new Thread(runnable,"t1");
t1.start(); // 启动线程
// 为了让 t1 线程充分运行 执行到 run() 方法内
Thread.sleep(1000);
/**
* 发送中断通知 设置中段标记为 true
*/
t1.interrupt();
}
}
上述代码可以让一个正在阻塞的线程是否中断,会抛出一个InterruptedException 异常, InterruptedException 会复位中断标记,不会中断线程,而在 catch 中可以决定如何处理这个中断请求,很明显这个处理中断请求的决定方是在当前线程。