实现原理:
新建线程类 TestThread,继承 Thread 类,重写 run 方法,主线程实例化 TestThread 对象,调用对象的 start() 方法,开启新线程,新线程会自动执行 run 方法的代码块,新线程何时执行 run 方法,取决于CPU的调度
适用场景:
多个线程各自执行各自的任务,任务之间互不烦扰,任务所需参数,在线程类实例化对象时,通过 构造器 设置参数,如:多个厨师炒不同的菜
package com.wei.thread;
import java.util.HashMap;
import java.util.Map;
public class TestThread extends Thread {
private Map params;
public TestThread(Map params) {
this.params = params;
}
@Override
public void run() {
StringBuilder builder = new StringBuilder();
params.forEach((k, v) -> {
builder.append(v).append("|");
});
System.out.println(Thread.currentThread().getName() + "-> 使用材料 (" + builder.toString() + ") 做菜");
}
public static void main(String[] args) {
// 定义菜谱食材
HashMap params1 = new HashMap<>();
HashMap params2 = new HashMap<>();
params1.put("tomato", "番茄");
params1.put("egg", "鸡蛋");
params2.put("beef", "牛肉");
// 线程类实例化对象时,传入参数
TestThread t1 = new TestThread(params1);
t1.setName("厨师1");
TestThread t2 = new TestThread(params2);
t2.setName("厨师2");
t1.start();
t2.start();
}
}
Lambda方式
package com.wei.thread;
import java.util.HashMap;
public class TestThreadLambda {
public static void main(String[] args) {
HashMap params1 = new HashMap<>();
HashMap params2 = new HashMap<>();
params1.put("tomato", "番茄");
params1.put("egg", "鸡蛋");
params2.put("beef", "牛肉");
Thread t1 = new Thread(() -> {
StringBuilder builder = new StringBuilder();
params1.forEach((k, v) -> {
builder.append(v).append("|");
});
System.out.println(Thread.currentThread().getName() + "-> 使用材料 (" + builder.toString() + ") 做菜");
},"厨师1");
Thread t2 = new Thread(() -> {
StringBuilder builder = new StringBuilder();
params2.forEach((k, v) -> {
builder.append(v).append("|");
});
System.out.println(Thread.currentThread().getName() + "-> 使用材料 (" + builder.toString() + ") 做菜");
}, "厨师2");
t1.start();
t2.start();
}
}
方式2:
实现原理:
新建 TestRunable 类,实现 Runable 接口,重写 run 方法,主线程实例化 TestRunable 对象;使用有参构造器,实例化 Thread 对象时,将 TestRunable 对象以参数形式传入,再调用 Thread 对象的 start() 方法,开启新线程,新线程会自动执行 run 方法的代码块,新线程何时执行 run 方法,取决于CPU的调度
适用场景:
多个线程共同操作一个任务,或共享共同的资源的情况,且不需要知道任务执行结果的场景。如:给偶像点赞
package com.wei.thread;
public class TestRunable implements Runnable {
String idol;
public TestRunable(String idol) {
this.idol = idol;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 给" + idol + " 点赞");
}
public static void main(String[] args) {
// 给同一个idol点赞
TestRunable tr = new TestRunable("周杰伦");
// 用户给偶像点赞
Thread t1 = new Thread(tr, "张三");
Thread t2 = new Thread(tr, "李四");
Thread t3 = new Thread(tr, "王五");
t1.start();
t2.start();
t3.start();
}
}
Lambda方式
package com.wei.thread;
public class TestRunableLambda{
public static void dianZan(String idol) {
System.out.println(Thread.currentThread().getName() + " 给" + idol + " 点赞");
}
public static void main(String[] args) {
// 给偶像点赞
Thread t1 = new Thread(()->{dianZan("周杰伦");}, "张三");
Thread t2 = new Thread(()->{dianZan("周结论");}, "李四");
Thread t3 = new Thread(()->{dianZan("周结论");}, "王五");
t1.start();
t2.start();
t3.start();
}
}
方式3:
实现原理:
新建 TestCallable 类,实现 Callable 接口,重写 call 方法,主线程实例化 TestCallable 对象;需要通过线程池进行代理调用,将 TestCallable 对象,提交到 线程池,线程池的线程会自动执行 call 方法的代码块,线程池中的线程何时执行 call 方法,取决于CPU的调度
适用场景:
多个线程共同操作一个任务,或共享同一个资源的情况,但需要返回任务执行结果的场景,如:用户抢票
package com.wei.thread; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TestCallable implements CallableLambda方式
package com.wei.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestCallableLambda {
private static int ticket = 2;
public static synchronized Map buyTicket(String user) {
Map result = new HashMap<>();
if (ticket <= 0) {
result.put(user, "票已售罄");
return result;
}
result.put(user, "买到票No:" + ticket);
ticket--;
return result;
}
public static void main(String[] args) throws Exception {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
// 模拟3个用户抢票
Future> user1 = threadPool.submit(() -> {
return buyTicket("张三");
});
Future> user2 = threadPool.submit(() -> {
return buyTicket("李四");
});
Future> user3 = threadPool.submit(() -> {
return buyTicket("王五");
});
System.out.println(user1.get());
System.out.println(user2.get());
System.out.println(user3.get());
threadPool.shutdown();
}
}
小结:
1、Thread 类、Runable接口、Callable接口 区别
- 继承 Thread 类,实例化 Thread 对象,调用对象的 start() 方法即可开启线程
- 实现 Runable接口 或 Callable接口 的类,实例化为对象后,需要将对象传入代理对象,由代理对象开启线程
- Runable接口实现类 的代理对象,可以是 Thread对象,也可以是 线程池对象
- Callable接口实现类 的代理对象,只能是 线程池对象
- Runable接口实现类,任务执行后 没有返回值
- Callable接口实现类,任务执行后 有返回值
虚拟机至少有两个线程,一个main线程,一个gc线程
用户线程: 应用层面实现业务逻辑的线程,如:main线程
守护线程: 在后台执行的线程,通过Daemon标记为true;如:gc线程
区别:
虚拟机需要等所有的用户线程执行完,才会退出
但不需要等待守护线程执行完毕,即可关闭资源
Thread.setDaemon(true); // 默认false,表示都是用户线程例子
package com.wei.thread;
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread godThread = new Thread(god);
Thread youThread = new Thread(you);
godThread.setDaemon(true);
godThread.start();
youThread.start();
}
}
class God implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("God 守护着你");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("每天开心活着 ^_^");
}
System.out.println("再见word");
}
}



