任务
多任务:
进程
线程
多线程
程序、进程、线程
进程Process和线程Thread
注意:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核处理器,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有了同时执行的错觉。
本章核心概念
三种创建方式:
普通方法调用和多线程:
package com.thread.demo01;
/*
创建线程的方式一:
1.继承Thread类
2.重写run()方法
3.调用start开启线程
注意:线程开启不一定立即执行,由CPU调度执行,无法人为干预
*/
public class ThreadTest01 extends Thread {
@Override
public void run() {
//run()方法线程体
for (int i = 0; i < 100; i++) {
System.out.println("我在看代码----" + i);
}
}
public static void main(String[] args) {
//main线程,主线程
//创建线程对象
ThreadTest01 threadTest01 = new ThreadTest01();
//调用start()方法开启线程,两个线程同时执行
threadTest01.start();
// threadTest01.run(); //先执行run()方法再执行后面,按顺序执行,只有一个线程
for (int i = 0; i < 500; i++) {
System.out.println("我在学习多线程----" + i);
}
}
}
谷歌下载Commons IO包,把commons-io.jar包复制到项目中,需要把包Add as Library添加到库。
package com.thread.demo01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//使用多线程同时下载图片
public class ThreadTest02 extends Thread {
private String url;
private String name;
public ThreadTest02(String url, String name) {
this.url = url; //网络图片地址
this.name = name; //保存的文件名
}
//下载图片线程的执行体
@Override
public void run() {
WebDownload webDownload = new WebDownload();
webDownload.download(url, name);
System.out.println("下载的文件名为:" + name);
}
public static void main(String[] args) {
//创建线程对象
ThreadTest02 thread01 = new ThreadTest02("https://pic3.zhimg.com/50/v2-5de178c64e85f84cd8c38590ab0e205f_720w.jpg?source=1940ef5c", "1.jpg");
ThreadTest02 thread02 = new ThreadTest02("https://pic2.zhimg.com/50/v2-6738a21df443d5c52f52df93464d2034_720w.jpg?source=1940ef5c", "2.jpg");
ThreadTest02 thread03 = new ThreadTest02("https://pica.zhimg.com/50/v2-898c55d1a93136b6c716ddfba4c8b7c9_720w.jpg?source=1940ef5c", "3.jpg");
//开启线程
//理想执行顺序是:先下载t1,然后t2,最后t3
//实际执行顺序是:t1,t3,t2,每次执行顺序可能都不一样
thread01.start();
thread02.start();
thread03.start();
}
}
//下载器
class WebDownload {
//下载方法
public void download(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,download方法出现问题");
}
}
}
创建线程推荐使用方式二,实现Runnable接口
package com.thread.demo01;
/*
创建线程方法二:实现Runnable接口,重写run()方法,执行线程需要丢入runnable接口
*/
public class ThreadTest03 implements Runnable{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 100; i++) {
System.out.println("我在看代码----" + i);
}
}
public static void main(String[] args) {
//创建Runnable接口的实现类对象
ThreadTest03 thread03 = new ThreadTest03();
//创建线程对象,通过线程对象开启线程,代理
// Thread thread = new Thread(thread03);
// thread.start();
new Thread(thread03).start();
for (int i = 0; i < 500; i++) {
System.out.println("我在学习多线程----" + i);
}
}
}
小结:
问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱!
package com.thread.demo01;
/*
多个线程同时操作同一个对象
场景:买火车票
发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱!
*/
public class ThreadTest05 implements Runnable{
//票数
private int ticketNums = 10;
@Override
public void run() {
while (true) {
if (ticketNums <= 0) {
break;
}
try {
//线程睡眠
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- + "张票");
}
}
public static void main(String[] args) {
ThreadTest05 ticket = new ThreadTest05();
new Thread(ticket, "小明").start();
new Thread(ticket, "小红").start();
new Thread(ticket, "黄牛").start();
}
}
package com.thread.demo01;
/*
模拟龟兔赛跑
*/
public class Race implements Runnable{
//胜利者
private static String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameOver(i);
//如果比赛结束了,就停止程序
if (flag) {
break;
}
System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");
}
}
//判断是否完成比赛
private boolean gameOver(int steps) {
//判断是否有胜利者
if (winner != null) { //已经有胜利者了
return true;
} else {
if (steps == 100) {
winner = Thread.currentThread().getName();
System.out.println("winner is " + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
package com.thread.demo02;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/*
线程创建方式三:实现Callable接口
使用Callable的好处
1.可以定义返回值类型
2.可以抛出异常
*/
public class CallableTest implements Callable<Boolean> {
private String url;
private String name;
public CallableTest(String url, String name) {
this.url = url; //网络图片地址
this.name = name; //保存的文件名
}
//下载图片线程的执行体
@Override
public Boolean call() {
WebDownload webDownload = new WebDownload();
webDownload.download(url, name);
System.out.println("下载的文件名为:" + name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程对象
CallableTest thread01 = new CallableTest("https://pic3.zhimg.com/50/v2-5de178c64e85f84cd8c38590ab0e205f_720w.jpg?source=1940ef5c", "1.jpg");
CallableTest thread02 = new CallableTest("https://pic2.zhimg.com/50/v2-6738a21df443d5c52f52df93464d2034_720w.jpg?source=1940ef5c", "2.jpg");
CallableTest thread03 = new CallableTest("https://pica.zhimg.com/50/v2-898c55d1a93136b6c716ddfba4c8b7c9_720w.jpg?source=1940ef5c", "3.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1 = ser.submit(thread01);
Future<Boolean> r2 = ser.submit(thread02);
Future<Boolean> r3 = ser.submit(thread03);
//获取结果
Boolean rs1 = r1.get();
Boolean rs2 = r2.get();
Boolean rs3 = r3.get();
//关闭服务
ser.shutdown();
}
}
//下载器
class WebDownload {
//下载方法
public void download(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,download方法出现问题");
}
}
}
事例:
package com.thread.demo03;
/*
静态代理模式总结:
真实对象和代理对象都要实现同一个接口
代理对象要代理真实角色
好处:
代理对象可以做很多真实对象做不了的事情
真实对象专注做自己的事情
*/
public class StaticProxy {
public static void main(String[] args) {
// You you = new You(); // 你要结婚
// WeddingCompany weddingCompany = new WeddingCompany(you);
new Thread( ()-> System.out.println("我爱你") ).start();
new WeddingCompany(new You()).HappyMarry();
// WeddingCompany weddingCompany = new WeddingCompany(new You());
// weddingCompany.HappyMarry();
}
}
interface Marry{
/*
人间四大喜事
久旱逢甘露
他乡遇故知
洞房花烛夜
金榜题名时
*/
void HappyMarry();
}
//真实角色,你去结婚
class You implements Marry {
@Override
public void HappyMarry() {
System.out.println("要结婚了,很开心!");
}
}
//代理角色,帮助你结婚
class WeddingCompany implements Marry {
//代理谁--》真实目标角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry(); //这就是真实对象
after();
}
private void after() {
System.out.println("结婚之前,布置现场");
}
private void before() {
System.out.println("结婚之后,收尾款");
}
}
推导Lambda表达式
package com.thread.demo04;
/*
推导Lambda表达式
*/
public class LambdaTest01 {
//3.静态内部类
static class Like2 implements ILike {
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like(); //接口指向实现类
like.lambda();
like = new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike {
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike() {
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
//6.用Lambda简化
like = ()-> {
System.out.println("i like lambda5");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface ILike {
void lambda();
}
//2.实现类
class Like implements ILike {
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
Lambda表达式简化
package com.thread.demo04;public class LambdaTest02 { //3.静态内部类 static class Love implements ILove { @Override public void love(int a) { System.out.println("i love you" + a); } } public static void main(String[] args) { //4.局部内部类 class Love implements ILove { @Override public void love(int a) { System.out.println("i love you" + a); } } ILove love = new Love(); love.love(2); //5.匿名内部类 ILove love2 = new ILove() { @Override public void love(int a) { System.out.println("i love you" + a); } }; love2.love(3); //6.Lambda表达式,简化 ILove love3 = (int a)-> { System.out.println("i love you" + a); }; love3.love(4); //简化1:去掉参数类型 ILove love4 = (a)-> { System.out.println("i love you" + a); }; love4.love(5); //简化2:去掉括号() ILove love5 = a-> { System.out.println("i love you" + a); }; love5.love(6); //简化3:去掉花括号{} ILove love6 = a-> System.out.println("i love you" + a); love6.love(7); /* 总结: Lambda表达式只能有一行代码的情况下才能简化成一行,如果有多行,那么就用代码块括起来。 使用Lambda表达式的前提,接口必须是函数式接口 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号()! */ }}//1.定义一个函数式接口interface ILove { void love(int a);}//2.实现类class Love implements ILove { @Override public void love(int a) { System.out.println("i love you" + a); }}
线程五大状态:
线程方法
package com.thread.demo05;/* 停止线程 1.建议线程正常停止--->利用次数,不建议死循环。 2.建议使用标志位--->设置一个标志位 3.不要使用stop或者destroy等过时方法,以及JDK不建议使用的方法 */public class ThreadStopTest01 implements Runnable { //1.设置一个标志位 private boolean flag = true; @Override public void run() { int i = 0; while (flag) { System.out.println("run...Thread" + i++); } } //2.设置一个公开的方法停止线程,改变标志位 public void stop() { this.flag = false; } public static void main(String[] args) { ThreadStopTest01 threadStop = new ThreadStopTest01(); new Thread(threadStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main" + i); if (i == 900) { //调用stop()方法改变标志位,让线程停止 threadStop.stop(); System.out.println("线程已停止"); } } }}
模拟网络延时:
package com.thread.demo05;/* 线程休眠 事例:模拟网络延时 模拟网络延时的作用:放大问题的发生性 */public class ThreadSleepTest01 implements Runnable { //票数 private int ticketNums = 10; @Override public void run() { while (true) { if (ticketNums <= 0) { break; } try { //线程睡眠,模拟延时 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- + "张票"); } } public static void main(String[] args) { ThreadSleepTest01 ticket = new ThreadSleepTest01(); new Thread(ticket, "小明").start(); new Thread(ticket, "小红").start(); new Thread(ticket, "黄牛").start(); }}
模拟倒计时:
package com.thread.demo05;import java.text.SimpleDateFormat;import java.util.Date;/* 线程休眠 事例:模拟倒计时 */public class ThreadSleepTest02 { public static void main(String[] args) { try { ThreadSleepTest02.tenDown(); } catch (InterruptedException e) { e.printStackTrace(); } //打印当前系统时间 Date start = new Date(System.currentTimeMillis()); //获取系统当前时间 while (true) { try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(start)); start = new Date(System.currentTimeMillis()); //更新当前时间 } catch (InterruptedException e) { e.printStackTrace(); } } } //模拟倒计时 public static void tenDown() throws InterruptedException { int num = 10; while (true) { Thread.sleep(1000); System.out.println(num--); if (num <= 0) { break; } } }}
package com.thread.demo05;/* 线程礼让 礼让不一定成功,看CPU心情 */public class ThreadYield { public static void main(String[] args) { MyYield myYield = new MyYield(); new Thread(myYield, "a").start(); new Thread(myYield, "b").start(); }}class MyYield implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + "线程开始执行"); Thread.yield(); //线程礼让 System.out.println(Thread.currentThread().getName() + "线程结束执行"); }}
package com.thread.demo05;/* 线程插队join() 可以想象成插队 */public class ThreadJoinTest01 implements Runnable { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("线程vip来了" + i); } } public static void main(String[] args) throws InterruptedException { //启动线程 ThreadJoinTest01 threadJoin = new ThreadJoinTest01(); Thread thread = new Thread(threadJoin); thread.start(); //主线程 for (int i = 0; i < 1000; i++) { if (i == 200) { thread.join(); //插队 } System.out.println("main" + i); } }}
package com.thread.demo05;/* 观察测试线程的状态 */public class ThreadStateTest01 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()-> { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("......."); }); //观察线程状态 Thread.State state = thread.getState(); System.out.println(state); //NEW //观察启动后 thread.start(); //启动线程 state = thread.getState(); System.out.println(state); //RUNNABLE while (state != Thread.State.TERMINATED) { //只要线程不终止,就一直输出状态 Thread.sleep(100); state = thread.getState(); //更新线程状态 System.out.println(state); //输出线程状态 } }}
package com.thread.demo05;/* 守护线程 事例:上帝守护着你 */public class ThreadDaemonTest01 { public static void main(String[] args) { God god = new God(); You you = new You(); Thread thread = new Thread(god); thread.setDaemon(true); //默认是false表示用户线程,正常的线程都是用户线程 thread.start(); //上帝守护线程启动 new Thread(you).start(); //你,用户线程启动 }}//上帝class God implements Runnable { @Override public void run() { while (true) { System.out.println("上帝保佑着你"); } }}//你class You implements Runnable { @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("你一生都开心的活着!"); } }}
多个线程操作同一个资源
并发
线程同步
队列和锁
同步方法的弊端
同步块
同步方法:
package com.thread.demo06;/* 不安全的买票 */public class ThreadUnsafeBuyTicket { public static void main(String[] args) { BuyTicket station = new BuyTicket(); new Thread(station, "机智如我").start(); new Thread(station, "难搞的你们").start(); new Thread(station, "可恶的黄牛").start(); }}class BuyTicket implements Runnable { //票 private int ticketNums = 10; boolean flag = true; //外部停止方式 @Override public void run() { //买票 while (flag) { buy(); } } //synchronized 同步方法,锁的是this private synchronized void buy() { //判断是否有票 if (ticketNums <= 0) { flag = false; return; } //模拟延时 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //买票 System.out.println(Thread.currentThread().getName() + "拿到第" + ticketNums-- + "张票"); }}
同步块:
package com.thread.demo06;/* 不安全的取钱 事例:两个人去银行取钱,需要账户 */public class ThreadUnsafeBank { public static void main(String[] args) { //账户 Account account = new Account(1000, "结婚基金"); Drawing you = new Drawing(account, 50, "你"); Drawing girlFriend = new Drawing(account, 100, "girlFriend"); you.start(); girlFriend.start(); }}//账户class Account { int money; //余额 String name; //卡名 public Account(int money, String name) { this.money = money; this.name = name; }}//银行:模拟取款class Drawing extends Thread { Account account; //取了多少钱 int drawingMoney; //现在手里有多少钱 int nowMoney; public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //取钱 //synchronized 默认锁的是this @Override public void run() { //同步块 //锁的对象就是变化的量 synchronized (account) { //判断有没有钱 if (account.money - drawingMoney < 0) { System.out.println(Thread.currentThread().getName() + "钱不够,取不了"); return; } //模拟延时,可以放大问题的发生性 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //卡内余额 = 余额 - 你取的钱 account.money = account.money - drawingMoney; //你手里的钱 nowMoney = nowMoney + drawingMoney; System.out.println(account.name + "余额为:" + account.money); System.out.println(this.getName() + "手里的钱:" + nowMoney);// System.out.println(Thread.currentThread().getName() + "手里的钱:" + nowMoney); } }}
死锁避免方法
package com.thread.demo07;/* 死锁 死锁:多个线程互相持有对方需要的资源,然后形成僵持 */public class DeadLock { public static void main(String[] args) { Makeup girl1 = new Makeup(0, "亚丝娜"); Makeup girl2 = new Makeup(1, "加藤惠"); girl1.start(); girl2.start(); }}//口红class Lipstick {}//镜子class Mirror {}//化妆class Makeup extends Thread { //需要的资源只有一份,用static来保证 static Lipstick lipstick = new Lipstick(); static Mirror mirror = new Mirror(); int choice; //选择 String girlName; //使用化妆品的人 Makeup(int choice, String girlName) { this.choice = choice; this.girlName = girlName; } @Override public void run() { //化妆 makeup(); } //化妆,互相持有对方的锁,就是需要拿到对方的资源 private void makeup() { if (choice == 0) { synchronized (lipstick) { //获得口红的锁 System.out.println(this.girlName + "获得口红的锁"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }//// synchronized (mirror) { //一秒钟后想获得镜子的锁// System.out.println(this.girlName + "获得镜子的锁");// } } //把同步块拿出来,就可以解决死锁问题 synchronized (mirror) { //一秒钟后想获得镜子的锁 System.out.println(this.girlName + "获得镜子的锁"); } } else { synchronized (mirror) { //获得镜子的锁 System.out.println(this.girlName + "获得镜子的锁"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }//// synchronized (lipstick) { //一秒钟后想获得口红的锁// System.out.println(this.girlName + "获得口红的锁");// } } synchronized (lipstick) { //一秒钟后想获得口红的锁 System.out.println(this.girlName + "获得口红的锁"); } } }}
package com.thread.demo08;import java.util.concurrent.locks.ReentrantLock;/* Lock锁 */public class LockTest { public static void main(String[] args) { LockTest2 lockTest2 = new LockTest2(); new Thread(lockTest2).start(); new Thread(lockTest2).start(); new Thread(lockTest2).start(); }}class LockTest2 implements Runnable { int ticketNums = 10; //定义Lock锁 private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { try { //加锁 lock.lock(); if (ticketNums > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticketNums--); } else { break; } } finally { //解锁 lock.unlock(); } } }}
生产者消费者模式
package com.thread.demo08;/* 生产者消费者模型-->利用缓冲区解决:管程法 要素:生产者,消费者,产品,缓冲区 */public class PCTest { public static void main(String[] args) { SynContainer container = new SynContainer(); new Producer(container).start(); new Consumer(container).start(); }}//生产者class Producer extends Thread { SynContainer container; public Producer(SynContainer container) { this.container = container; } //生产 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("生产了" + i + "只鸡"); container.push(new Chicken(i)); } }}//消费者class Consumer extends Thread { SynContainer container; public Consumer(SynContainer container) { this.container = container; } //消费 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了-->" + container.pop().id + "只鸡"); } }}//产品class Chicken { int id; //产品编号 public Chicken(int id) { this.id = id; }}//缓冲区class SynContainer { //需要一个容器的大小 Chicken[] chickens = new Chicken[10]; //容器计数器 int count = 0; //生产者放入产品 public synchronized void push(Chicken chicken) { //如果容器满了,就需要等待消费者消费 if (count == chickens.length) { //通知消费者消费,生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有满,我们就要丢入产品 chickens[count] = chicken; count++; //可以通知消费者消费了 this.notifyAll(); } //消费者消费产品 public synchronized Chicken pop() { //判断是否能消费 if (count == 0) { //等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果可以消费 count--; Chicken chicken = chickens[count]; //吃完了,通知生产者生产 this.notifyAll(); return chicken; }}
package com.thread.demo08;/* 生产者消费者模型2-->利用标志位解决:信号灯法 */public class PCTest02 { public static void main(String[] args) { Program program = new Program(); new actor(program).start(); new audience(program).start(); }}//生产者-->演员class actor extends Thread { Program program; public actor(Program program) { this.program = program; } @Override public void run() { for (int i = 0; i < 20; i++) { if (i % 2 == 0) { this.program.play("快乐大本营播放中"); } else { this.program.play("抖音,记录美好生活"); } } }}//消费者-->观众class audience extends Thread { Program program; public audience(Program program) { this.program = program; } @Override public void run() { for (int i = 0; i < 20; i++) { program.watch(); } }}//产品-->节目class Program{ //演员表演,观众等待 true //观众观看,演员等待 false String voice; //表演的节目 boolean flag = true; //表演 public synchronized void play(String voice) { if (!flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演员表演了:" + voice); //通知观众观看 this.notifyAll(); //通知唤醒 this.voice = voice; this.flag = !this.flag; } //观看 public synchronized void watch() { if (flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("观看了:" + voice); //通知演员表演 this.notifyAll(); this.flag = !this.flag; }}
package com.thread.demo08;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/* 线程池 */public class ThreadPoolTest { public static void main(String[] args) { //1.创建服务,创建线程池 //newFixedThreadPool 参数为:线程池大小 ExecutorService service = Executors.newFixedThreadPool(10); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //2.关闭连接 service.shutdown(); }}class MyThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()); }}
线程实现的三个方式,锁
package com.thread.demo09;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/* 总结 线程实现的三个方式 */public class AllInOne { public static void main(String[] args) { new MyThread1().start(); new Thread(new MyThread2()).start(); FutureTask<Integer> futureTask = new FutureTask<>(new MyThread3()); new Thread(futureTask).start(); try { Integer integer = futureTask.get(); System.out.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }}//1.继承Thread类class MyThread1 extends Thread { @Override public void run() { System.out.println("MyThread1"); }}//2.实现Runnable接口class MyThread2 implements Runnable { @Override public void run() { System.out.println("MyThread2"); }}//3.实现Callable接口class MyThread3 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("MyThread3"); return 100; }}
原文:https://www.cnblogs.com/hongchengg/p/15239547.html