多线程
继承Thread类
package com.Yoona.demo01;
//创建方式一:继承Thread类,重写run方法,调用start开启线程
//注意:线程开启不一定立即执行,由cpu调度执行
public class TestThread1 extends Thread
{
@Override
public void run()
{
//run方法线程体
for (int i = 0; i < 20; i++)
{
System.out.println("我在看代码-----" + i);
}
}
public static void main(String[] args)
{
//main线程,主线程
//创建一个线程对象,调用start方法开启线程 同时进行
//如果调用run方法,先运行run再返回主程序,单线程
TestThread1 testThread1 = new TestThread1();
testThread1.start();
for (int i = 0; i < 2000; i++)
{
System.out.println("我在学习多线程---" + i);
}
}
}
网图下载
package com.Yoona.demo01;
import org.apache.commons.io.FileUtils;
import org.xml.sax.ext.Attributes2;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习Thread,实现多线程同步下载图片
public class TestThread2 extends Thread
{
private String url;//网络图片地址
private String name;//保存的文件名
public TestThread2(String url, String name)
{
this.url = url;
this.name = name;
}
//下载图片线程的执行体
@Override
public void run()
{
WebDownload webDownload = new WebDownload();
webDownload.downloader(url, name);
System.out.println("下载了文件名为:" + name);
}
public static void main(String[] args)
{
TestThread2 t1 = new TestThread2("https://profile.csdnimg.cn/8/5/B/3_segegse", "Yoona");
TestThread2 t2 = new TestThread2("https://profile.csdnimg.cn/8/5/B/3_segegse", "is");
TestThread2 t3 = new TestThread2("https://profile.csdnimg.cn/8/5/B/3_segegse", "my girlfriend");
//同时执行
t1.start();
t2.start();
t3.start();
}
}
//下载器
class WebDownload
{
//下载方法
public void downloader(String url, String name)
{
try
{//让url变成一个文件
FileUtils.copyURLToFile(new URL(url), new File(name));
}
catch (IOException e)
{
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
实现Runnable接口
package com.Yoona.demo01;
//创建线程方式2:实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口实现类,调用start方法
//Runnable 只有run方法
//推荐方法二 不被单继承局限
public class TestThread3 implements Runnable
{
@Override
public void run()
{
//run方法线程体
for (int i = 0; i < 20; i++)
{
System.out.println("我在看代码-----" + i);
}
}
public static void main(String[] args)
{
//创建runnable接口的实现类对象
TestThread3 testThread3 = new TestThread3();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread = new Thread(testThread3);
thread.start();
//new Thread(testThread3).start();
for (int i = 0; i < 2000; i++)
{
System.out.println("我在学习多线程---" + i);
}
}
}
小结
继承Thread类
-
子类继承Thread类
-
启动线程:子类对象.start()
-
不建议使用:避免OOP单继承局限性
实现Ruunable接口
-
实现接口Runnable具有多线程能力
-
启动线程:传入目标对象+Thread对象.start()
-
推荐使用:避免单继承局限性,方便灵活,方便同一个对象被多个线程使用
初识并发问题
package com.Yoona.demo01;
//多个线程同时操作同一个对象
//买火车票的例子
//发现问题 多个线程操纵同一个资源 数据紊乱
public class TestThread4 implements Runnable
{
//票数
int tickerNums = 10;
@Override
public void run()
{
while (true)
{
if (tickerNums <= 0)
break;
try
{
Thread.sleep(200);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->拿到了第" + tickerNums-- + "张票");
}
}
public static void main(String[] args)
{
TestThread4 ticket = new TestThread4();
new Thread(ticket, "小明").start();
new Thread(ticket, "老师").start();
new Thread(ticket, "黄牛党").start();
}
}
龟兔赛跑
package com.Yoona.demo01;
public class Race implements Runnable
{
//胜利者
private static String winner;
@Override
public void run()
{
for (int i = 0; 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();
}
}
实现callable接口(了解即可)
package com.Yoona.demo02;
import com.Yoona.demo01.TestThread2;
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 TestCallable implements Callable<Boolean>
{
private String url;//网络图片地址
private String name;//保存的文件名
public TestCallable(String url, String name)
{
this.url = url;
this.name = name;
}
//下载图片线程的执行体
@Override
public Boolean call()
{
WebDownload webDownload = new WebDownload();
webDownload.downloader(url, name);
System.out.println("下载了文件名为:" + name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException
{
TestThread2 t1 = new TestThread2("https://profile.csdnimg.cn/8/5/B/3_segegse", "Yoona");
TestThread2 t2 = new TestThread2("https://profile.csdnimg.cn/8/5/B/3_segegse", "is");
TestThread2 t3 = new TestThread2("https://profile.csdnimg.cn/8/5/B/3_segegse", "my girlfriend");
//创捷执行服务 线程池
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行 启动
Future<Boolean> r1 = (Future<Boolean>) ser.submit(t1);
Future<Boolean> r2 = (Future<Boolean>) ser.submit(t2);
Future<Boolean> r3 = (Future<Boolean>) ser.submit(t3);
//获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
//关闭服务
ser.shutdown();
}
}
class WebDownload
{
public void downloader(String url, String name)
{
try
{//让url变成一个文件
FileUtils.copyURLToFile(new URL(url), new File(name));
}
catch (IOException e)
{
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
Lamda表达式
使用原因
- 避免匿名内部类定义过多
- 可以让你的代码看起来很简洁
- 去掉了一堆没有意义的代码,只留下核心的逻辑
函数式接口的定义
- 任何接口,如果只包含一个抽象方法,就是一个函数式接口
- 对于函数式接口,我们可以通过lamda表达式来创建该对象
package com.Yoona.lambda;
/*
*推导lambda表达式
* */
public class TestLambda1
{
//静态内部类
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();
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");
}
}
package com.Yoona.lambda;
public class TestLambda2
{
public static void main(String[] args)
{
ILove love = (int a) ->
{
System.out.println("I love Yoona forever" + a);
};
//上面的自动覆盖了
love = a -> System.out.println("i love Yoona" + a);
love.love(1314);
///总结:
// lambda表达式如果只有一行可以省略括号 否则得用代码块包裹
// 必须是函数式接口 一个方法
// 多个参数也可以去掉参数类型,要去就都去掉 必须加括号(a,b)
}
}
interface ILove
{
void love(int a);
}
静态代理模式
package com.Yoona.staticproxy;
//静态代理模式总结:
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实角色
//好处
//代理对象可以做很多真实对象做不了的事
public class StaticProxy
{
public static void main(String[] args)
{
You you = new You();
you.HappyMarry();
new Thread(() -> System.out.println("我爱你啊")).start();//实现了Thread 和括号里都实现了 runnable接口
new WeddingCompany(new You()).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 before()
{
System.out.println("结婚之前,布置现场");
}
private void after()
{
System.out.println("结婚之后,收尾款");
}
}
线程停止
-
不推荐使用JDK提供的stop(),destroy()方法 已废弃
-
推荐线程自己停止下来
-
建议使用一个标志位来进行终止变量,当flag = false,则终止线程运行
package com.Yoona.state; //测试stop //1.建议线程正常停止--->利用次数,不建议死循环 //2.建议使用标志位-->设置一个标志位 //3.不要使用stop或者destroy等过时方法 public class TestStop 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) { TestStop testStop = new TestStop(); new Thread(testStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main " + i); if (i == 900) { //调用stop方法 切换标志位,让线程停止 testStop.stop(); System.out.println("线程停止"); } } } }
线程休眠
- sleep指定当前线程阻塞的毫秒数
- sleep存在异常InterruptedException
- sleep时间达到后线程进入就绪状态
- sleep可以模拟网络延时,倒计时等
- 每一个对象都有一个锁,sleep不会释放锁
package com.Yoona.state; import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep { public static void tenDown() throws InterruptedException { int num = 10; while (true) { Thread.sleep(1000); System.out.println(num--); if (num <= 0) { break; } } } public static void main(String[] args) throws InterruptedException { //模拟倒计时 //tenDown(); Date startTime = new Date(System.currentTimeMillis()); while (true) { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:MM:SS").format(startTime));//更新当前时间 } } }
线程礼让
- 礼让线程 ,让当前执行的线程停止,但不阻塞
- 让线程运行状态转为就绪状态
- 让cpu重新调度,礼让不一定成功
package com.Yoona.state;
//测试礼让线程
//礼让不一定成功,看cpu成功
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.Yoona.state;
//测试Join
public class TestJoin implements Runnable
{
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 == 200)
{
//插队
thread.join();
}
System.out.println("main" + i);
}
}
@Override
public void run()
{
for (int i = 0; i < 1000; i++)
{
System.out.println("线程vip来了" + i);
}
}
}
观测线程状态
package com.Yoona.state;
//观察测试线程的状态
public class TestState
{
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);//Run
while (state != Thread.State.TERMINATED)
{
//只要线程不终止就一直输出状态
Thread.sleep(1000);
state = thread.getState();
System.out.println(state);
}
}
}
//线程只能start一次
线程优先级
-
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪一个线程来执行
-
线程的优先级用数字来表示,范围从1到10
- Thread.MIN_PRIORITY = 1
- Thread.MAX_PRIORITY = 10
- Thread.NORM_PRIORITY = 5
-
使用以下方式改变或者获取优先级
getPriority() setPriority(int a)
-
一般都是5
package com.Yoona.state;
public class TestPriority extends Thread
{
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);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
//先设置优先级,再启动
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
t4.start();
}
}
class MyPriority implements Runnable
{
@Override
public void run()
{
System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
}
}
守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
package com.Yoona.state;
//测试守护线程
//上帝守护你
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("goodbye world");
}
}
线程同步(synchronized)
同步块 :synchronized(obj){}
锁线程竞争的资源
- 买票
package com.Yoona.syn;
//不安全的买票
//线程不安全,有负的
public class UnsafeBuyTicket
{
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)
{
try
{
buy();
//模拟延时
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
}
}
//synchronized 同步方法,锁的是this
private synchronized void buy() throws InterruptedException
{
//判断是否邮票
if (ticketNums <= 0)
{
flag = false;
return;
}
System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
}
}
- 取钱
package com.Yoona.syn;
//不安全的取钱
//两个人去银行取其那,账户
public class UnsafeBank
{
public static void main(String[] args)
{
//账户
Account account = new Account(100, "结婚基金");
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;
}
@Override
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);
//Thread.currentThread().getName()
System.out.println(this.getName() + "手里的钱" + nowMoney);
}
}
}
- 集合
package com.Yoona.syn;
import java.util.ArrayList;
import java.util.List;
//线程不安全的集合
public class UnsafeList
{
public static void main(String[] args) throws InterruptedException
{
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++)
{
new Thread(() ->
{
synchronized (list)
{
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(1000);
System.out.println(list.size());
}
}
- 拓展
package com.Yoona.syn;
import java.util.concurrent.CopyOnWriteArrayList;
//测试JUC安全类型的集合
public class TestJUC
{
public static void main(String[] args) throws InterruptedException
{
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10000; i++)
{
new Thread(() ->
{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(3000);//主线程休眠 保证子线程先执行完
System.out.println(list.size());
}
}
死锁
死锁产生的四个条件:
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而被阻塞时,对一伙的的资源保持不放
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干进取之间形成一种头尾相接的循环等待资源关系
package com.Yoona.deadlock;
//死锁:多个线程互相抱着对方需要的资源,然后形成僵持
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 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(2000);
synchronized (lipstick)
{
//一秒钟之后获得口红的锁
System.out.println(this.girlName + "获得口红的锁");
}
}
}
}
}
Lock锁
synchronized和 Lock的对比
- Lock是显式锁,手动开启和关闭,synchronized是隐式锁,出了作用域自动是释放。
- Lock只有代码块锁,synchronized有代码块和方法锁
- 使用Lock锁。JVM将花费较少的时间来实现调度,性能更好。并且有更好的扩展性
- 优先使用顺序:Lock > 同步代码块 > 同步方法
package com.Yoona.advance;
import java.util.concurrent.locks.ReentrantLock;
//测试Lock锁
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锁
private ReentrantLock lock = new ReentrantLock();
//延时放在锁外面
@Override
public void run()
{
while (true)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
lock.lock();//加锁
try
{
if (ticketNums > 0)
{
System.out.println(Thread.currentThread().getName() + "拿到了" + ticketNums--);
}
else
{
break;
}
}
finally
{
//解锁
lock.unlock();
}
}
}
}
线程通信(生产者消费者问题)
- wait 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁
- notify 唤醒一个处于等待状态的线程
- 均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则抛出异常
管程法
package com.Yoona.advance;
//测试生产者 消费者模型 管程法
//生产者 消费者 产品 缓冲区
public class TestPC
{
public static void main(String[] args)
{
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者
class Productor extends Thread
{
SynContainer container;
public Productor(SynContainer container)
{
this.container = container;
}
//生产
@Override
public void run()
{
for (int i = 0; i < 100; i++)
{
try
{
container.push(new Chicken(i));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("生产了" + 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++)
{
try
{
System.out.println("消费了第" + container.pop().id + "只鸡");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
//产品
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) throws InterruptedException
{
//如果容器满了,就要等待消费者消费
if (count == chickens.length)
{
this.wait();
//通知消费者消费,生产者等待
}
//如果没有满,我们就丢入产品
chickens[count++] = chicken;
//可以通知消费者消费了,
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop() throws InterruptedException
{
//判断能否消费
if (count == 0)
{
//等待生产者生产,消费者消费
this.wait();
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
//通知生产者生产
this.notifyAll();
return chicken;
}
}
信号灯法
package com.Yoona.advance;
//测试生产者消费者问题2:信号灯法,标志位解决
public class TestPC2
{
public static void main(String[] args)
{
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者->演员
class Player extends Thread
{
TV tv;
public Player(TV tv)
{
this.tv = tv;
}
@Override
public void run()
{
for (int i = 0; i < 20; i++)
{
if (i % 2 == 0)
{
try
{
this.tv.play("快乐大本营播放中");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
else
{
try
{
this.tv.play("抖音记录美好生活");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
//消费者->观众
class Watcher extends Thread
{
TV tv;
public Watcher(TV tv)
{
this.tv = tv;
}
@Override
public void run()
{
for (int i = 0; i < 20; i++)
{
try
{
tv.watch();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
//产品->节目
class TV
{
//演员表演,观众等待
//观众观看,演员等待
String voice;//表演的节目
boolean flag = true;
//表演
public synchronized void play(String voice) throws InterruptedException
{
if (!flag)
{
this.wait();
}
System.out.println("演员表演了" + voice);
//通知观众观看
this.notifyAll();//通知唤醒
this.voice = voice;
this.flag = !this.flag;
}
//观看
public synchronized void watch() throws InterruptedException
{
if (flag)
{
this.wait();
}
System.out.println("观看了" + voice);
//通知演员表演
this.notifyAll();
this.flag = !this.flag;
}
}
线程池
- 背景:经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影像很大
- 思路:提前创建好多个线程,放入线程池中,使用时直接获取,手机用完放回池中。课以避免频繁的创建销毁,实现重复利用。
- 好处:
- 提高响应速度(减少了创建新的线程的时间)
- 降低资源的消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程的管理
- corePoolSize:核心池大小
- maxmumPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多久时间后会终止
使用线程池
- ExecutorService和Executors
- ExecutorService:真正的线程池接口 常见子类 ThreadPoolExecutor
- void execute(Runnable command):执行任务,没有返回值,一般用来执行Runna
- Futuresubmit(Callabletask):执行任务,有返回值,一般执行Callable
- void shutdown():关闭线程池
- Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池。
package com.Yoona.advance;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//测试线程池
public class TestPool
{
public static void main(String[] args)
{
//1.创建服务,创建线程
//newFixedThreadPool 参数为:线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//执行 Runnable接口的实现类
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());
}
}