多线程
6.1.1 进程和线程
- ***进程***是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
- 线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。
- Thread class
- Runnable接口
- Callable接口
-
创建线程的方式一:继承Thread类,重写run()方法,调用start并开启线程
-
线程不一定立即执行,由CPU调度
6.1.2 继承Thread类
-
package com.thread; //创建线程的方式一:继承Thread类,重写run()方法,调用start并开启线程 public class Demo01 extends Thread{ public static void main(String[] args) throws InterruptedException { Demo01 demo01 = new Demo01(); demo01.start(); for (int i = 0; i < 1000; i++) { System.out.println("我在学习多线程--"+i); demo01.sleep(100); } } @Override public void run() { for (int i = 0; i < 200; i++) { System.out.println("我在看代码--"+i); try { this.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
不建议使用:避免OOP单继承局限性
6.1.3 实现Runnable接口
-
package com.thread; //创建线程的方式二,实现Runnable接口,重写run()方法,调用start并开启线程 public class Demo03 implements Runnable{ @Override public void run() { for (int i = 0; i < 200; i++) { System.out.println("代码===="+i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Demo03 demo03 = new Demo03(); new Thread(demo03).start(); for (int i = 0; i < 1000; i++) { System.out.println("多线程===="+i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
推荐使用:避免单继承局限性,灵活方便,方便同一个对象呗多个线程使用
6.1.4 实例:龟兔赛跑
-
package com.thread; //模拟龟兔赛跑 public class Race implements Runnable{ private static String winner; @Override public void run() { for (int i = 0; i <= 100; i++) { //模拟兔子睡觉 if (Thread.currentThread().getName()=="兔子" && i%10==0){ try { Thread.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } } if (Thread.currentThread().getName()=="乌龟" && 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; } 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(); } }
6.1.5 实现Callable接口
- 可以定义返回值
- 了解即可
6.1.6 静态代理
-
package com.thread; public class StaticProxy { public static void main(String[] args) { You you = new You(); WeddingCompany weddingCompany = new WeddingCompany(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("结婚前"); } }
6.2.1 Lamda表达式
-
new Thread(()->System.out.println("多线程学习")).start();
-
package com.thread; public class TestLambda { //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"); } }
-
函数式接口:一个接口只包含一个抽象方法
-
interface ILike{ void lambda(); }
-
public static void main(String[] args){ ILove love = null; love = a->System.out.println("I Love You--->"+a); love.love(520); } interface ILove{ void love(int a); }
- lambda表达式只能在有一行代码的情况下才能简化为一行
- 前提是接口为函数式接口
- 多个参数时也可以去掉参数类型,要去掉就都去掉
6.2.2 线程的五大状态
- 新生状态
- 就绪状态
- 阻塞状态
- 运行状态
- 死亡状态
-
线程的停止:不建议使用官方的stop方法
package com.thread; public class TestStop implements Runnable{ //设置一个标志位 private boolean flag = true; @Override public void run() { int i = 0; while (flag){ System.out.println("running....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){ //3.调用stop方法切换标志位,让线程停止 testStop.stop(); System.out.println("线程停止了"); } } } }
-
Sleep
-
打印当前系统时间
package com.thread; import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep2 { public static void CountDown() throws InterruptedException { int num = 10; while (true){ Thread.sleep(1000); System.out.println(num--); if (num<=0){ break; } } } public static void main(String[] args) { Date startTime = new Date(System.currentTimeMillis()); while (true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
倒计时
package com.thread; public class TestSleep3 { public static void CountDown() throws InterruptedException { int num = 10; while (true){ Thread.sleep(1000); System.out.println(num--); if (num<=0){ break; } } } public static void main(String[] args) { try { CountDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }
-
6.2.3 线程三大方法
-
sleep(睡眠)
- 不会释放锁
-
yield(礼让)
-
礼让不一定成功
-
package com.thread; 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()+"线程停止执行"); } }
-
-
join(让线程等待)
-
package com.thread; public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("线程VIP来了"+i); } } public static void main(String[] args) { TestJoin testJoin = new TestJoin(); Thread thread = new Thread(testJoin); thread.start(); for (int i = 0; i < 1000; i++) { if (i==200){ try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("main"+i); } } }
-
会释放锁
-
6.2.4 观察线程状态
-
package com.thread; //观察线程的状态 public class TestState { public static void main(String[] args) { 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);//新生态 //管查启动后 thread.start(); state=thread.getState(); System.out.println(state);//运行态 while (state!=Thread.State.TERMINATED){//只要state不停止 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } state=thread.getState();//更新状态 System.out.println(state); } } }
6.3.1 线程的优先级
-
线程优先级高不一定先执行,但是先执行的可能性更高,执不执行看CPU
-
优先级范围:1-10(默认为5)
-
优先级数字越大优先级越高
-
package com.thread; public class TestPriority { public static void main(String[] args) { MyPriority myPriority = new MyPriority(); Thread t1 = new Thread(myPriority); Thread t2 = new Thread(myPriority); Thread t3 = new Thread(myPriority); Thread t4 = new Thread(myPriority); System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); t1.start(); t2.setPriority(1); t2.start(); t3.setPriority(4); t3.start(); t4.setPriority(Thread.MAX_PRIORITY); t4.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); } }
6.3.2 守护线程
-
thread.setDaemon(true);//设置守护线程
-
package com.thread; //测试守护线程 //上帝守护你 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);//设置守护线程 thread.start(); Thread thread1 = new Thread(you); thread1.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("Goodbye World!"); } }
6.4.1 线程同步
-
锁机制(synchronized)
-
线程不安全两大案例:
-
买票
-
package com.syn; //买票 public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket station = new BuyTicket(); new Thread(station,"1").start(); new Thread(station,"2").start(); new Thread(station,"黄牛").start(); } } class BuyTicket implements Runnable{ private int ticketNums = 10; boolean flag = true; @Override public void run() { while (flag){ buy(); } } private 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.syn; public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100, "基金"); Drawing me = new Drawing(account, 50, "你"); Drawing wife = new Drawing(account, 100, "wife"); me.start(); wife.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 currentMoney; public Drawing(Account account,int drawingMoney,String name){ super(name); this.account=account; this.drawingMoney=drawingMoney; } @Override public void run() { if (account.money<drawingMoney) { System.out.println(Thread.currentThread().getName() + "钱余额不足"); return; } try { Thread.sleep(100);//放大问题的发生性 } catch (InterruptedException e) { e.printStackTrace(); } account.money -=drawingMoney; currentMoney+=drawingMoney; System.out.println(account.name+"目前余额为:"+account.money); System.out.println(this.getName()+"手里的钱为:"+this.currentMoney); } }
-
-
同步:
-
//obj是指需要锁的资源,需要增加或者减少 synchronized(obj){ //这里面写线程的操作 }
-
6.4.2 死锁
-
产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个线程使用
- 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:线程已获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
-
package com.syn; public class DeadLock { public static void main(String[] args) { Makeup g1 = new Makeup(0, "灰姑娘"); Makeup g2 = new Makeup(1, "白雪公主"); g1.start(); g2.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() { 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(1000); synchronized (lipstick){ System.out.println(this.girlName+"获得了口红的锁"); } } } } }
-
在上面的例子中,g1和g2分别获得了口红和镜子的锁,还想获得对方的锁,导致了死锁的发生
-
解决办法:
-
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(1000); } synchronized (lipstick){ System.out.println(this.girlName+"获得了口红的锁"); } } }
- 将第二同步锁放在第一个同步锁之外,这样就不会出现拥有一个锁的同时还想获得另一个锁的情况,就能有效的解决死锁问题
-
6.4.3 Lock(锁)
-
ReentrantLock(可重入锁)
-
class A{ private final ReentrantLock lock = new ReentrantLock(); public void m(){ lock.lock(); try{ //保证线程安全的代码; }finally{ lock.unlock(); //如果同步代码有异常,要将unlock()写入finally语句块 } } }
6.4.4 wait()和notify()
- wait()表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁
- notify()唤醒一个处于等待状态的线程
- wait(long timeout)
- notifyAll()唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程有限调度