1. 线程类Thread
在 JDK 中代表线程的就只有 Thread 类
准确地讲,创建线程只有一种方式那就是构造 Thread 类,而实现线程的执行单元则有两种方式,第一种是重写 Thread 的 run(), 第二种是实现 Runnable 接口的 run(), 并且将 Runnable 实例用作构造 Thread 的参数
1.1 java.lang.Thread
public class Thread implements Runnable {
// 线程名字
private volatile String name;
private int priority;
// 线程的唯一标识符
private long tid;
private Runnable target;
private ThreadGroup group;
// 线程的执行单元 run()
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
1.2 创建线程的两种方式
- 方式一:继承 Thread 类
- 方式二:实现Runnable接口
2. 继承 Thread 类
@Slf4j
public class MyThread extends Thread {
/**
* this.getId() 和 this.getName() 有局限性,必须 extends Thread 才能使用,因为这是父类中的方法
*/
@Override
public void run() {
log.info("线程id: " + this.getId() + "; 线程名称: " + this.getName());
log.info("Thread name: " + Thread.currentThread().getName());
}
}
调用
@Test
public void run() {
MyThread thread = new MyThread();
thread.start();
}
打印结果:
18:29:28.230 [Thread-1] INFO juc.MyThread - 线程id: 14; 线程名称: Thread-1
18:29:28.235 [Thread-1] INFO juc.MyThread - Thread name: Thread-1
2.2 匿名内部类方式
- 语法
new 父类() { 子类 };
- 匿名类是一个表达式,因此在定义的最后用分号结束
例如:通过匿名类方式创建线程
@Test
public void run() {
Thread thread = new Thread() {
// 子类重写父类的run()
@Override
public void run() {
log.info("run...");
}
};
thread.start();
}
打印结果:
18:39:39.258 [Thread-1] INFO juc.JUCDemo - run...
也可写成如下:
@Test
public void run() {
new Thread() {
@Override
public void run(){
log.info("run...");
}
}.start();
}
2.3 其他方式:将线程对象作为构造参数
@Test
public void run() {
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}
3. 实现 Runnable 接口
@Slf4j
public class MyThread implements Runnable {
@Override
public void run() {
log.info("run...");
}
}
调用
@Test
public void run() {
MyThread myThread = new MyThread();
// 创建线程对象
Thread thread = new Thread(myThread, "test");
thread.start();
}
打印结果:
18:33:39.150 [test] INFO juc.MyThread - run...
3.2 匿名内部类方式
@Test
public void run() {
Runnable runnable = new Runnable() {
@Override
public void run() {
log.info("run...");
}
};
Thread thread = new Thread(runnable);
Thread thread2= new Thread(runnable, "t2");
thread.start();
thread2.start();
}
打印结果:
18:37:00.045 [Thread-1] INFO juc.JUCDemo - run...
18:37:00.045 [t2] INFO juc.JUCDemo - run...
4. 实现 Callable 接口
@Test
public void run() {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return Stream.iterate(1, n -> n + 1)
.limit(100)
.reduce(0, Integer::sum);
}
};
// Callable 有返回值,需要 FutureTask 来接收执行结果
FutureTask<Integer> task = new FutureTask<>(callable);
new Thread(task).start();
Integer result = null;
try {
// 接收运行的结果: get()是阻塞的,等call()执行完才会返回
result = task.get();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(result);
}
5. Runable vs Callable
- Runnable 的 run() 无返回值
- Callable 的 call() 有返回值,并且有声明异常
public interface Runnable {
public abstract void run();
}
public interface Callable<V> {
V call() throws Exception;
}
6. 其他
6.1 设置线程名称
方式一:直接 setName()
MyThread thread = new MyThread();
thread.start();
thread.setName("Thread name");
方式二:在构造方法里设置
public class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
}
网友评论