简单介绍:多线程是CPU同时处理多个任务
现实场景:人边吃饭边玩手机,属于多线程的范畴
简单介绍:进程包含线程
实际场景:看视频时,视频播放,声音播放,字幕加载
进程由系统分配,线程则是实际的功能执行
代码中模拟的多线程,他是由单核CPU执行只是切换的很块,每个一点点执行,看起来像是同时执行。
真正的多线程是指,多CPU,既多核执行
实际场景:当秒杀商品时,就是多个线程在执行,多线程互相争抢资源,就需要给他们排队,来控制资源的抢夺。
注意点:线程启动之后并不会立即执行,将会由CPU调度执行
package Thread; /** * @className: ThreadTest1 * @description: * @createDate: 2021年06月25日 11:11:22 * @author: ns */ public class ThreadTest1 extends Thread { public static void main(String[] args) { ThreadTest1 threadTest1 = new ThreadTest1(); threadTest1.start(); for (int i = 0; i < 2000; i++) { System.out.println("看代码" + i); } } public void run() { for (int i = 0; i < 10; i++) { System.out.println("学习多线程代码" + i); } } }
运行效果
包下载路径
https://search.maven.org/artifact/org.apache.directory.studio/org.apache.commons.io/2.4/jar
package Thread; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; /** * @className: ThreadTest2 * @description: * @createDate: 2021年06月25日 14:08:56 * @author: ns */ public class ThreadTest2 extends Thread { private String url; private String name; public ThreadTest2(String url, String name) { this.url = url; this.name = name; } public void run() { WebDownLoader webDownLoader = new WebDownLoader(); webDownLoader.downLoader(url, name); System.out.println("下载了文件名为" + name); } public static void main(String[] args) { ThreadTest2 threadTest1 = new ThreadTest2("https://www.www.zyiz.net/i/ll/?i=2021061516385914.png#pic_center", "图1.png"); ThreadTest2 threadTest2 = new ThreadTest2("https://www.www.zyiz.net/i/ll/?i=20210615175631519.png#pic_center", "图2.png"); ThreadTest2 threadTest3 = new ThreadTest2("https://www.www.zyiz.net/i/ll/?i=20210616110215957.png#pic_center", "图3.png"); threadTest1.start(); threadTest2.start(); threadTest3.start(); } } class WebDownLoader { public void downLoader(String url, String name) { try { FileUtils.copyURLToFile(new URL(url), new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO异常"); } } }
package Thread; /** * @className: ThreadTest3 * @description: * @createDate: 2021年06月25日 14:30:08 * @author: ns */ public class ThreadTest3 implements Runnable{ public static void main(String[] args) { ThreadTest3 threadTest1 = new ThreadTest3(); //代理 new Thread(threadTest1).start(); for (int i = 0; i < 2000; i++) { System.out.println("看代码" + i); } } public void run() { for (int i = 0; i < 10; i++) { System.out.println("学习多线程代码" + i); } } }
总结:避免单继承的局限性,推荐使用Runnable实现多线程,方便同一个对象被多个线程使用
package org.ck.thread.callable; import org.ck.thread.ThreadTest2; import org.ck.thread.WebDownLoader; import java.util.concurrent.*; /** * @className: TestCallAble * @description: 实现callable 接口 * @createDate: 2021年06月25日 17:39:45 * @author: ns */ public class TestCallAble implements Callable<Boolean> { private String url; private String name; public TestCallAble(String url, String name) { this.url = url; this.name = name; } public static void main(String[] args) { TestCallAble threadTest1 = new TestCallAble("https://www.www.zyiz.net/i/ll/?i=2021061516385914.png#pic_center", "图1.png"); TestCallAble threadTest2 = new TestCallAble("https://www.www.zyiz.net/i/ll/?i=20210615175631519.png#pic_center", "图2.png"); TestCallAble threadTest3 = new TestCallAble("https://www.www.zyiz.net/i/ll/?i=20210616110215957.png#pic_center", "图3.png"); ExecutorService ser = Executors.newFixedThreadPool(3); Future<Boolean> r1 = ser.submit(threadTest1); Future<Boolean> r2 = ser.submit(threadTest2); Future<Boolean> r3 = ser.submit(threadTest3); try { System.out.println(r1.get()); System.out.println(r2.get()); System.out.println(r3.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } ser.shutdown(); } @Override public Boolean call() { WebDownLoader webDownLoader = new WebDownLoader(); webDownLoader.downLoader(url, name); System.out.println("下载了文件名为" + name); return true; } }
总结:相比Runnable和Thread实现的线程,callable,使用了线程池,并让线程有了返回结果。
模拟抢票
package Thread; /** * @className: ThreadTest4 * @description: * @createDate: 2021年06月25日 14:42:41 * @author: ns */ public class ThreadTest4 implements Runnable { private int ticketNums = 10; 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) { ThreadTest4 ticket = new ThreadTest4(); new Thread(ticket, "小明").start(); new Thread(ticket, "老师").start(); new Thread(ticket, "黄牛党").start(); } }
运行结果
不应该有-1
package org.ck.thread.proystatic; /** * @className: StaticProxy * @description: 静态代理:代理类似面向切面编程,注解和这个很像,找到横切面 * 真实对象与代理角色都要实现同一个接口 * 代理对象可以帮助真实对象做琐事 * 真实对象只专注自己的事 * @createDate: 2021年06月28日 11:05:39 * @author: ns */ public class StaticProxy { public static void main(String[] args) { //线程实现 new Thread(()-> System.out.println("爱")).start(); //结婚代理 new WeddingCompany(new You()).HappyMarry(); /* //自己结婚 You you = new You(); //代理结婚 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("布置现场"); } }
静态代理总结:代理和代理对象通过实现同一个接口完成静态代理。属于AOP面向切面编程。
函数式接口 案例
@FunctionalInterface public interface Runnable { public abstract void run(); }
测试类
package org.ck.thread.lambda; /** * @className: LambdaTest * @description: * @createDate: 2021年06月28日 11:39:20 * @author: ck */ public class LambdaTest { //静态内部类 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"); } }
运行结果
测试类2
package org.ck.thread.lambda; /** * @className: LambadLoveTest * @description: * @createDate: 2021年07月03日 18:18:49 * @author: ck */ public class LambdaLoveTest { public static void main(String[] args) { /* Love love = new Love(); love.love(2);*/ int b = 20; ILove iLove = (a) -> { System.out.println("测试" + a); }; iLove = a -> { System.out.println("测试" + a); }; // iLove = a -> System.out.println("测试" + a); iLove.love(b); } } interface ILove { void love(int a); } class Love implements ILove { @Override public void love(int a) { System.out.println("love one" + a); } }
运行结果
new Thread() 创建状态
start就绪状态
run运行状态
sleep,wait 阻塞
dead run自然结束就是死亡
package org.ck.thread.status; /** * @className: TestStop * @description: 测试stop 线程正常停止,不建议死循环 * 建议使用标志位-->设置一个标志位 * 不要使用stop或者destroy等过时或JDK不建议的方法 * @createDate: 2021年07月07日 11:19:45 * @author: ck */ public class TestStop implements Runnable { //1.设置标志 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) { TestStop testStop = new TestStop(); new Thread(testStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main" + i); if (i== 900) { testStop.stop(); System.out.println("线程该停止了"); } } } }
运行结果
PS:run中的i与main方法中的i不同,所以不用管run的I走到了哪里
黄牛抢票模拟
package org.ck.thread.status; /** * @className: TestSleep * @description: 模拟网络延时 * @createDate: 2021年07月07日 11:33:05 * @author: ck */ public class TestSleep implements Runnable{ private int ticketNums = 10; 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) { TestSleep ticket = new TestSleep(); new Thread(ticket, "小明").start(); new Thread(ticket, "老师").start(); new Thread(ticket, "黄牛党").start(); } }
运行结果
sleep自带锁
倒计时模拟
package org.ck.thread.status; /** * @className: TestSleep * @description: 模拟网络延时 * @createDate: 2021年07月07日 11:33:05 * @author: ck */ public class TestSleep implements Runnable{ private int ticketNums = 10; 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) { TestSleep ticket = new TestSleep(); new Thread(ticket, "小明").start(); new Thread(ticket, "老师").start(); new Thread(ticket, "黄牛党").start(); } }
运行结果
package org.ck.thread.status; /** * @className: TestYield * @description: 线程礼让不一定成功 * @createDate: 2021年07月07日 15:08:59 * @author: ck */ public class TestYield { 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 org.ck.thread.status; /** * @className: TestJoin * @description: 测试join方法 * @createDate: 2021年07月07日 15:26:59 * @author: ck */ public class TestJoin implements Runnable { @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("线程vip来了" + i); } } public static void main(String[] args) throws InterruptedException { TestJoin testJoin = new TestJoin(); Thread thread = new Thread(testJoin); thread.start(); for (int i = 0; i < 500; i++) { if (i == 10) { thread.join();//插队 } System.out.println("main" + i); } } }
运行结果
NEW 创建状态
RUNNABLE
运行状态
BLOCKED
阻塞状态
WAITING
等待状态
TIMED_WAITING
等待零一个线程达到指定时间
TERMINATED
退出的线程
package org.ck.thread.status; /** * @className: TestState * @description: * @createDate: 2021年07月07日 15:54:22 * @author: ck */ public class TestState { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0; i < 10; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("///"); }); //观察状态 Thread.State state = thread.getState(); System.out.println(state); //观察启动后 thread.start();//启动 state = thread.getState(); System.out.println(state);//run while (state != Thread.State.TERMINATED) { Thread.sleep(100); state = thread.getState(); System.out.println(state); } } }
运行结果
package org.ck.thread.status; /** * @className: TestPriority * @description: * @createDate: 2021年07月07日 16:02:41 * @author: ck */ public class TestPriority { public static void main(String[] args) { //主线程默认优先级 System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread t1 = new Thread(myPriority); Thread t2 = new Thread(myPriority); Thread t3 = new Thread(myPriority); Thread t4 = new Thread(myPriority); //设置优先级启动 t1.start(); t2.setPriority(1); t2.start(); t3.setPriority(Thread.MAX_PRIORITY); t3.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); } }
运行结果
package org.ck.thread.status; /** * @className: TestDaemon * @description: 测试守护线程 * @createDate: 2021年07月07日 16:11:27 * @author: ck */ public class TestDaemon { 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("你一生都开心的活着"); } System.out.println("=======hello,world"); } }
运行结果
总结:虚拟机回确保主线程执行完毕,但不会确认守护线程一定能执行完成(守护线程常有,GC)
不安全的取钱
package org.ck.thread.syn; /** * @className: UnsafeBank * @description: 不安全的取钱 * @createDate: 2021年07月08日 18:25:59 * @author: ck */ public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100,"基金"); Drawing you = new Drawing(account,50,"你"); Drawing youFriend = new Drawing(account,100,"你朋友"); you.start(); youFriend.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; } public void run() { //判断有没有钱 if (account.money - drawingMoney < 0) { System.out.println(Thread.currentThread().getName() + "钱不够"); return; } //sleep 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); } }
运行结果
问题:基金余额不能-50
不安全的买票
package org.ck.thread.syn; /** * @className: UnsafeBuyTicket * @description: 不安全的买票 * * @createDate: 2021年07月08日 18:18:04 * @author: ck */ public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket, "苦逼的我").start(); new Thread(buyTicket, "牛逼的你们").start(); new Thread(buyTicket, "可恶的黄牛党").start(); } } class BuyTicket implements Runnable { private int ticketNums = 10; boolean flag = true;//外部停止方式 @Override public void run() { while (flag) { try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void buy() throws InterruptedException { if (ticketNums <= 0) { flag = false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--); } }
问题不应该有两次1
不安全的List
package org.ck.thread.syn; import java.util.ArrayList; import java.util.List; /** * @className: UnSafeList * @description: 线程不安全的集合 * @createDate: 2021年07月08日 18:44:00 * @author: ck */ public class UnSafeList { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(() -> { //两个线程操作了同一个位置,导致有数据被覆盖了 list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
运行结果
问题:能明显观察到少了两个
多个线程往同一个位置插入了数据
通过队列+锁来实现多线程的安全
安全的取钱
package org.ck.thread.syn; /** * @className: UnsafeBank * @description: 不安全的取钱 * @createDate: 2021年07月08日 18:25:59 * @author: ck */ public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100, "基金"); Drawing you = new Drawing(account, 50, "你"); Drawing youFriend = new Drawing(account, 100, "你朋友"); you.start(); youFriend.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; } public void run() { synchronized (account) { //判断有没有钱 if (account.money - drawingMoney < 0) { System.out.println(Thread.currentThread().getName() + "钱不够"); return; } //sleep 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); } } }
总结:是用户发起的取钱行为那就锁用户,让请求的用户排好队。
安全的买票
package org.ck.thread.syn; /** * @className: UnsafeBuyTicket * @description: 不安全的买票 * * @createDate: 2021年07月08日 18:18:04 * @author: ck */ public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket, "苦逼的我").start(); new Thread(buyTicket, "牛逼的你们").start(); new Thread(buyTicket, "可恶的黄牛党").start(); } } class BuyTicket implements Runnable { private int ticketNums = 10; boolean flag = true;//外部停止方式 @Override public void run() { while (flag) { try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } //synchronized 同步方法 锁的是this private synchronized void buy() throws InterruptedException { //判断是否有票 if (ticketNums <= 0) { flag = false; return; } //模拟延时 Thread.sleep(100); //买票 System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--); } }
安全的集合
package org.ck.thread.syn; import java.util.ArrayList; import java.util.List; /** * @className: UnSafeList * @description: 线程不安全的集合 * @createDate: 2021年07月08日 18:44:00 * @author: ck */ public class UnSafeList { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(() -> { //两个线程操作了同一个位置,导致有数据被覆盖了 synchronized (list) { list.add(Thread.currentThread().getName()); } }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
package org.ck.thread.syn; /** * @className: DeadLock * @description: 死锁 * @createDate: 2021年07月15日 10:03:12 * @author: ck */ public class DeadLock { public static void main(String[] args) { Makeup girl = new Makeup(0,"灰姑凉"); Makeup girl1 = new Makeup(1,"白雪公主"); girl.start(); girl1.start(); } } class Lipstick { } class Mirror { } class Makeup extends Thread { static Lipstick lipstick = new Lipstick(); static Mirror mirror = new Mirror(); int choice;//选择 String girlName; public Makeup(int choice, String girlName) { this.choice = choice; this.girlName = girlName; } @Override public void run() { try { makeup(); } catch (InterruptedException e) { e.printStackTrace(); } //化妆 } //化妆 互相持有对方的锁 private void makeup() throws InterruptedException { if (choice == 0) { synchronized (lipstick) { System.out.println(this.girlName + "获得口红的锁"); Thread.sleep(1000); synchronized (mirror) { System.out.println(this.girlName + "获得镜子的锁"); } } }else{ synchronized (mirror) { System.out.println(this.girlName + "获得镜子的锁"); Thread.sleep(2000); synchronized (lipstick) { System.out.println(this.girlName + "获得口红的锁"); } } } } }
灰姑凉想获得镜子
白雪公主想要获得口红
但是镜子在白雪公主手上
口红在灰姑凉手上
就造成了死锁
解决方案:白雪公主和灰姑凉用完各自的东西,将其放回去就不会死锁了。
private void makeup() throws InterruptedException { if (choice == 0) { synchronized (lipstick) { System.out.println(this.girlName + "获得口红的锁"); Thread.sleep(1000); } synchronized (mirror) { System.out.println(this.girlName + "获得镜子的锁"); } }else{ synchronized (mirror) { System.out.println(this.girlName + "获得镜子的锁"); Thread.sleep(2000); } synchronized (lipstick) { System.out.println(this.girlName + "获得口红的锁"); } } }
运行结果
package org.ck.thread.lock; import java.util.concurrent.locks.ReentrantLock; /** * @className: TestLock * @description: * @createDate: 2021年07月16日 18:12:23 * @author: ck */ public class TestLock { public static void main(String[] args) { TestLock2 testLock2 = new TestLock2(); new Thread(testLock2).start(); new Thread(testLock2).start(); new Thread(testLock2).start(); } } class TestLock2 implements Runnable { int ticketNums = 10; //定义lock锁 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(); } } } }
运行结果
synchronized和Lock的差异
synchronized
java 关键字
会自动释放锁
lock
只是一个类
需要手动释放锁
lock相比synchronize的可操作性更强
总结
package org.ck.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @className: ThreadNew * @description: 回顾线程的创建 * @createDate: 2021年07月19日 11:26:59 * @author: ck */ public class ThreadNew { public static void main(String[] args) { new MyThread1().start(); new Thread(new MyThread2()).start(); FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3()); new Thread(futureTask).start(); Integer integer = null; try { integer = futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println(integer); } } //1.继承Thread类 class MyThread1 extends Thread{ public void run(){ System.out.println("MyThread1"); } } //2.实现Runnable接口 class MyThread2 implements Runnable{ public void run(){ System.out.println("MyThread2"); } } //实现CallAble class MyThread3 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("MyThread3"); return 100; } }
以上内容学自B站狂神JAVA
https://www.bilibili.com/video/BV1V4411p7EF?from=search&seid=13950488010332720509