Version: Next

线程创建

Thread、Runnable、Callable

创建线程的三种方式:

  • Thread类:继承Thread类
  • Runnable接口:实现Runnable接口
  • Callable接口:实现Callable接口

继承Thread类

自身实现了Runnable接口

步骤:

  1. 自定义线程类继承Thread
  2. 重写run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动线程
public class Demo01Thread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 20; i++) {
System.out.println("run线程体 -> " + i);
}
}
public static void main(String[] args) {
//主线程
//创建一个线程对象
Demo01Thread thread = new Demo01Thread();
//调用start()方法,开启线程
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程 ->" + i);
}
}
}
主线程 ->0
run线程体 -> 0
主线程 ->1
run线程体 -> 1
主线程 ->2
run线程体 -> 2
主线程 ->3
run线程体 -> 3
主线程 ->4
run线程体 -> 4
主线程 ->5
run线程体 -> 5
主线程 ->6
run线程体 -> 6
主线程 ->7
run线程体 -> 7
主线程 ->8
主线程 ->9
run线程体 -> 8
主线程 ->10
主线程 ->11
主线程 ->12
主线程 ->13
主线程 ->14
主线程 ->15
主线程 ->16
主线程 ->17
主线程 ->18
主线程 ->19
run线程体 -> 9
run线程体 -> 10
run线程体 -> 11
run线程体 -> 12
run线程体 -> 13
run线程体 -> 14
run线程体 -> 15
run线程体 -> 16
run线程体 -> 17
run线程体 -> 18
run线程体 -> 19

可以看到线程交替运行

实现Runnable接口

步骤

  1. 定义自己的类,实现Runnable接口
  2. 实现run()方法,编写线程执行体
  3. 创建线程对象,传入Runnable实现类对象,new Thread(Xxx)
  4. 调用start()方法启动线程
public class Demo02Runnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("run方法 -> " + i);
}
}
public static void main(String[] args) {
Demo02Runnable myRunnable = new Demo02Runnable();
//穿件线程对象,通过线程对象来开启我们的线程,代理
// Thread构造方法可以接受一个实现Runnable接口的类
new Thread(myRunnable).start();
for (int i = 0; i < 10; i++) {
System.out.println("主进程 -> " + i);
}
}
}
主进程 -> 0
run方法 -> 0
主进程 -> 1
run方法 -> 1
主进程 -> 2
run方法 -> 2
run方法 -> 3
主进程 -> 3
run方法 -> 4
主进程 -> 4
run方法 -> 5
主进程 -> 5
run方法 -> 6
主进程 -> 6
run方法 -> 7
主进程 -> 7
主进程 -> 8
run方法 -> 8
主进程 -> 9
run方法 -> 9

初识并发问题

public class Demo03Multi implements Runnable {
private int ticketNum = 10;
@Override
public void run() {
while (true) {
if (ticketNum <= 0) {
System.out.println("卖完了");
break;
}
System.out.println(Thread.currentThread().getName() +
"拿到了第" +
ticketNum-- +
"张票");
}
try {
//模拟延时
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Demo03Multi demo03 = new Demo03Multi();
new Thread(demo03, "thread1").start();
new Thread(demo03, "thread2").start();
new Thread(demo03, "thread3").start();
}
}
thread1拿到了第9张票
thread3拿到了第9张票
thread2拿到了第10张票
thread3拿到了第7张票
thread1拿到了第8张票
thread3拿到了第5张票
thread2拿到了第6张票
thread3拿到了第3张票
thread1拿到了第4张票
卖完了
thread3拿到了第1张票
卖完了
thread2拿到了第2张票
卖完了

可以看到线程1和线程3都拿到第9张票,这说明多个线程同时操作一个资源时可能出现错误,称为线程不安全

使用Lambda表达式书写

public class Demo05MultiWithLambda {
private static int ticketNum = 10;
public static void main(String[] args) {
new Thread(() -> {
while (true) {
if (ticketNum <= 0) {
System.out.println("卖完了");
break;
}
System.out.println(Thread.currentThread().getName() +
"拿到了第" +
ticketNum-- +
"张票");
}
try {
//模拟延时
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t1").start();
}
}

实现Callable接口

步骤:

  1. 实现Callable接口,需要返回值类型
  2. 重写call()方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  5. 提交执行:Future<Boolean> result1 = ser.submit(t1)
  6. 获取结果:boolean r1 = result1.get()
  7. 关闭服务:ser.shutdownNow()
public class Demo04Callable implements Callable {
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " | callable call() -> " + i);
}
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Demo04Callable t1 = new Demo04Callable();
Demo04Callable t2 = new Demo04Callable();
Demo04Callable t3 = new Demo04Callable();
//创建执行服务
ExecutorService service = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> result1 = service.submit(t1);
Future<Boolean> result2 = service.submit(t2);
Future<Boolean> result3 = service.submit(t3);
//获取结果
Boolean resultBool1 = result1.get();
Boolean resultBool2 = result2.get();
Boolean resultBool3 = result3.get();
//关闭服务
service.shutdown();
}
}
pool-1-thread-1 | callable call() -> 0
pool-1-thread-1 | callable call() -> 1
pool-1-thread-1 | callable call() -> 2
pool-1-thread-1 | callable call() -> 3
pool-1-thread-1 | callable call() -> 4
pool-1-thread-1 | callable call() -> 5
pool-1-thread-2 | callable call() -> 0
pool-1-thread-2 | callable call() -> 1
pool-1-thread-2 | callable call() -> 2
pool-1-thread-2 | callable call() -> 3
pool-1-thread-2 | callable call() -> 4
pool-1-thread-2 | callable call() -> 5
pool-1-thread-2 | callable call() -> 6
pool-1-thread-2 | callable call() -> 7
pool-1-thread-3 | callable call() -> 0
pool-1-thread-2 | callable call() -> 8
pool-1-thread-1 | callable call() -> 6
pool-1-thread-1 | callable call() -> 7
pool-1-thread-1 | callable call() -> 8
pool-1-thread-1 | callable call() -> 9
pool-1-thread-2 | callable call() -> 9
pool-1-thread-3 | callable call() -> 1
pool-1-thread-3 | callable call() -> 2
pool-1-thread-3 | callable call() -> 3
pool-1-thread-3 | callable call() -> 4
pool-1-thread-3 | callable call() -> 5
pool-1-thread-3 | callable call() -> 6
pool-1-thread-3 | callable call() -> 7
pool-1-thread-3 | callable call() -> 8
pool-1-thread-3 | callable call() -> 9

小结

继承Thread类

  • 子类继承Thread类具备多线程能力
  • 启动线程:子类对象.start()

不建议使用:避免OOP单继承局限性

实现Runnable接口

  • 实现接口Runnable具有多线程能力
  • 启动线程:传入目标对象 -> new Thread(目标对象).start()

推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用