多线程
多线程thread
重要概念
-
程序,进程,线程
-
程序在操作系统运行就是一个进程,一个进程可以有多个线程
-
多线程指的是两个线程同时运行
和之前的线性执行普通方法有区别
-
main方法为主线程,系统入口,没创建线程也存在的线程之一,还有gc,垃圾回收线程
创建进程
- 继承(extends)Thread类
- 实现(implements)Runnable类
- 实现Callable类
-
继承(extends)Thread类(Thread类实现了Runnable)
方法:继承Thread类,重写run方法,创建对象调用start方法开启线程
调用start()方法是开启一个线程,调用run()方法只是根据顺序调用方法
start()的结果是类似多线程,同时执行,两输出交叉出现,具体调用由cpu决定
run方法为线程体,线程入口点
package lesson01; public class Thread_Demo01 extends Thread{ @Override public void run() { for (int i = 0; i < 500; i++) { System.out.println("0看代码"+i); } } public static void main(String[] args) { Thread_Demo01 threadDemo01 = new Thread_Demo01(); threadDemo01.start(); for (int i = 0; i < 1000; i++) { System.out.println("1学编程"+i); } } }
-
多线程下载网图(用了工具类FileUtils.copyURLToFile)
-
先百度下载commons-io-2.17.0.jar
-
创建lib工具文件夹,导入commons-io-2.17.0.jar,右键添加到库
package com.zhm.demo01; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; public class Test_Thread02 extends Thread{ private String url;//下载图片url private String name;//保存文件名 public Test_Thread02(String url,String name){ this.url = url; this.name = name; } //执行体 @Override public void run() { WebDownloader webDownloader = new WebDownloader(); webDownloader.downloader(url,name); System.out.println("下载了文件名为" + name); } public static void main(String[] args) { Test_Thread02 p1 = new Test_Thread02("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2023/10/16/kuangstudyb67cc598-9e1a-4e17-a7de-f4ecdd7f8d32.jpg", "1.jpg"); Test_Thread02 p2 = new Test_Thread02("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudyb62b0ccb-55b5-4572-b067-347314beac15.jpg","2.jpg"); Test_Thread02 p3 = new Test_Thread02("https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2021/07/21/kuangstudy69ec9992-bed7-4eec-a550-5fe2aeb44737.jpg", "3.jpg"); p1.start(); p2.start(); p3.start(); } } class WebDownloader{ public void downloader(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { System.out.println("downloader方法异常"); throw new RuntimeException(e); } } }
-
实现(implements)Runnable接口(interface)
方法:实现Runnable接口,实现run方法,创建实例对象,传入实例对象创建Thread对象.start()开启线程
package com.zhm.demo01; public class Test_Thread03 implements Runnable{ @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("2这是2"); } } public static void main(String[] args) { Test_Thread03 testThread03 = new Test_Thread03(); // Thread thread = new Thread(testThread03); // thread.start(); new Thread(testThread03).start(); for (int i = 0; i < 1000; i++) { System.out.println("1这是1"); } } }
Thread thread = new Thread(testThread03); thread.start();
等于
new Thread(testThread03).start();
extends Thread和implements Runnable区别
例子
一个对象被多个线程使用
多线程抢票,并发问题
package com.zhm.demo01; public class TestThread04 implements Runnable{ private int ticketNums = 10; @Override public void run() { while (true){ //无票退出循环 if (ticketNums <=0){ break; } try { //延时防止某一线程全部抢完 Thread.sleep(200); } catch (InterruptedException e) { throw new RuntimeException(e); } //Thread.currentThread()返回当前线程本身,getname()方法是线程名字 System.out.println(Thread.currentThread().getName()+"拿到了第"+(ticketNums--)+"张票"); } } public static void main(String[] args) { TestThread04 ticket = new TestThread04(); new Thread(ticket,"学生").start(); new Thread(ticket,"老师").start(); new Thread(ticket,"黄牛").start(); } }
龟兔赛跑案例
一个race对象
两个线程名,兔子和乌龟
用距离,判断游戏是否结束,结束两者不再跑,输出胜利者名字
run方法输出兔子乌龟跑的距离
package com.zhm.demo01; //龟兔赛跑,两个线程比谁先到达100 public class TestThread05 implements Runnable{ // private static int steps; private static String winnerName; @Override public void run() { for (int i = 1; i < 102; i++) { if (Thread.currentThread().getName().equals("兔子") && i%10==0){ try { Thread.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } } boolean flag = gameover(i); if (flag){ break; } System.out.println(Thread.currentThread().getName()+"-->到达第"+i+"m"); } } //判断游戏是否结束,输出谁赢了,返回true代表结束 public boolean gameover(int steps){ if (winnerName!=null){ return true; } if (steps>=101){ winnerName = Thread.currentThread().getName(); System.out.println("winner is "+winnerName); return true; } return false; } public static void main(String[] args) { TestThread05 race = new TestThread05(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
-
实现(implements)Callable接口(interface)
和实现Runnable接口区别在多了两步,开启服务和关闭服务,重写call方法有返回值要抛出异常(对应run方法)
(静态)代理模式(多线程底部实现原理)
-
分为接口和两个实现类
-
两个类分为真实类和代理类,都要实现同一个接口
-
代理类需要定义真实类,重写实现方法中传入真实类对象
-
真实类就是普通实现类,实现接口方法
-
好处在于真实类可以专注自身,代理类可以灵活添加操作
-
多线程底部实现原理
-
定义MyRunnable类实现Runnable接口,为真实类,实现重写run方法
-
Thread类实现Runnable接口,为代理类,(传入真实类实例)实现重写run方法
-
//多线程接口例子 MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); //上=下 new Thread(new TestThread03()).start(); //对照 //婚庆例子 You you = new You(); WeddingCompany weddingCompany = new WeddingCompany(you); weddingCompany.happyMarry(); //上=下 new WeddingCompany(new You()).happyMarry();
-
婚庆例子
package com.zhm.demo02; import com.zhm.demo01.TestThread01; import com.zhm.demo01.TestThread02; import com.zhm.demo01.TestThread03; public class StaticProxy { public static void main(String[] args) { You you = new You(); WeddingCompany weddingCompany = new WeddingCompany(you); weddingCompany.happyMarry(); new WeddingCompany(new You()).happyMarry(); // new Thread(new TestThread03()).start(); } } class You implements Marry{ @Override public void happyMarry() { System.out.println("我是you,要结婚了吗"); } } class WeddingCompany implements Marry{ private Marry marry; public WeddingCompany(Marry marry){ this.marry = marry; } @Override public void happyMarry() { before(); this.marry.happyMarry(); System.out.println(marry.getClass()); System.out.println(this.marry.getClass()); after(); } private void after() { System.out.println("结婚完了,那完蛋了"); } private void before() { System.out.println("结婚之前,还能逆转"); } } interface Marry{ void happyMarry(); }
Lambda表达式
-
主要是实现Runnable会用到
-
要求:接口是函数式接口,接口里需要实现的方法只有一个
-
一共有5种实现接口方法
-
外部类
-
静态内部类(加static的成员内部类)
-
方法内部类
-
匿名内部类
-
lambda表达式 ()->{方法体}(匿名内部类简化)
ILove love = new ILove() { @Overeide public void love(int a){ System.out.println(a); } } //-------------上 = 下---------------------------- ILove love = (int a) -> {System.out.println(a);}
-
-
package com.zhm.lambda; public class LambdaTest01 { //2静态内部类 static class Love2 implements ILove { @Override public void love(int a) { System.out.println("love"+a); } } public static void main(String[] args) { ILove love = new Love1(); love.love(1); love = new Love2(); love.love(2); //3方法内部类 class Love3 implements ILove{ @Override public void love(int a) { System.out.println("love"+a); } } love = new Love3(); love.love(3); //4匿名内部类 love = new ILove() { @Override public void love(int a) { System.out.println("love"+a); } }; love.love(4); //5lambda表达式 love = (int a) -> { System.out.println("love"+a); }; love.love(5); //最简版本 //去参数定义(int)要求是多个参数要去都去,去方法括号{}要求是方法只有一行代码 love = a -> System.out.println("love"+a); } } interface ILove { void love(int a); } //1实现类 class Love1 implements ILove { @Override public void love(int a) { System.out.println("love"+a); } }
如果不是实现接口的类,想要把匿名内部类化简为lambda表达式,格式有不同
Thread thread = new Thread(()->{}); thread.start(); //= new Thread(()->{}).start; //= Runnable runnable = new Runnable(){ //重新run方法 };//匿名内部类 new Thread(runnbale).start; //= Runnable runnable = ()->{ //run方法体 }; new Thread(runnbale).start;
线程状态
-
状态有5种
-
创建状态,就绪状态,运行状态,阻塞状态,死亡状态
-
线程停止
-
推荐定义标志位,学方法让线程自己停下,不要用已经jdk废弃的方法(@Deprecated标识代表废弃)
-
package com.zhm.state; public class TestStop implements Runnable{ //用标志位停止 private boolean flag = true; @Override public void run() { int i = 1; while (flag){ System.out.println("Thrend is running..."+(i++)); } } //线程停止方法,线程自己调用方法停止最安全 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("mainThread is running..."+i); if (i==900) { testStop.stop(); System.out.println("线程停止"); } } } }
-
线程休眠
-
sleep(1000)代表线程阻塞1000ms=1s,1s后线程进入就绪状态等待cpu调度
-
主要应用于网络延时,放大问题发送;倒计时;时钟
//倒计时 package com.zhm.state; public class TestSleep { public static void main(String[] args) { try { countDown(); } catch (InterruptedException e) { throw new RuntimeException(e); } } public static void countDown() throws InterruptedException { int num = 10; while (num>=0){ System.out.println(num--); Thread.sleep(1000); } } }
//1秒1次输出当前时间 package com.zhm.state; import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep2 { public static void main(String[] args) throws InterruptedException { Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间 //1秒1次输出时间 while (true){ System.out.println(new SimpleDateFormat("yy:HH:mm:ss").format(startTime)); Thread.sleep(1000); startTime = new Date(System.currentTimeMillis()); } } }
-
礼让yield方法
-
让当前线程由运行变为就绪状态,再由cpu重新调度
package com.zhm.state; 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()+"->start"); Thread.yield();//礼让,让当前线程由运行->就绪 System.out.println(Thread.currentThread().getName()+"->end"); } }
-
插队join方法
-
类似现实生活插队,强制让插队线程最先运行到结束,再让cpu调度
-
用的不多
package com.zhm.state; 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==50){ thread.join(); } System.out.println("主线程"+i); } } }
-
线程状态在代码中的表现
-
Thread.State 枚举类型
-
线程状态。 线程可以处于以下状态之一: NEW 尚未启动的线程处于此状态。 RUNNABLE 在Java虚拟机中执行的线程处于此状态。 BLOCKED 被阻塞等待监视器锁定的线程处于此状态。 WAITING 正在等待另一个线程执行特定动作的线程处于此状态。 TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 TERMINATED 已退出的线程处于此状态。 一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。
package com.zhm.state; public class TestState { //观察线程状态 public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ //一共运行5s for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); if (i == 4){ System.out.println("/////"); } } catch (InterruptedException e) { throw new RuntimeException(e); } } }); 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){ state = thread.getState(); //sleep后状态变为TIMED_WAITING //TIMED_WAITING System.out.println(state); //1s监测10次状态 Thread.sleep(100); } } }
-
线程优先级
-
范围1-10,超出会抛出异常,越高cpu调度可能性越大(只是可能性)
-
默认是5
package com.zhm.state; public class TestPriority { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + Thread.currentThread().getPriority()); MyPriority p = new MyPriority(); Thread t1 = new Thread(p); Thread t2 = new Thread(p); Thread t3 = new Thread(p); Thread t4 = new Thread(p); Thread t5 = new Thread(p); Thread t6 = new Thread(p); //设置优先级要在线程运行之前(1~10) t1.start(); t2.setPriority(Thread.MAX_PRIORITY);//10 t2.start(); t3.setPriority(Thread.MIN_PRIORITY);//1 t3.start(); t4.setPriority(Thread.NORM_PRIORITY);//5 t4.start(); t5.setPriority(8); t5.start(); t6.setPriority(4); t6.start(); } } class MyPriority implements Runnable{ @Override public void run() { //获得当前线程名字和优先级 System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); } }
-
守护线程
-
普通的线程都是用户线程,setdaemon定义为true为守护线程
-
虚拟机会执行用户直到结束,守护线程不会管结不结束
-
应用于后台记录操作日志,监控内存,垃圾回收
package com.zhm.state; public class TestDaemon { public static void main(String[] args) { You you = new You(); God god = new God(); Thread thread = new Thread(god); thread.setDaemon(true);//设置为守护线程 thread.start(); new Thread(you).start(); } } class You implements Runnable{ @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("活着"); } System.out.println("goodbye"); } } class God implements Runnable{ @Override public void run() { while (true){ System.out.println("永生"); } } }
线程同步
-
不同线程操作同一资源可能会出现并发问题,不安全
-
要排队+锁机制解决
-
好处:安全 坏处:效率降低
-
线程不安全案例
-
多个线程买票
package com.zhm.syn; //多个人同时买票 //可能会出现0,-1这种不安全情况,原因是多个线程同时操作票数为1时的内存 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 ticketsNum = 10; private boolean flag = true;//线程停止符,true代表运行 @Override public void run() { while (flag){ buyTickets(); } } //买票 public void buyTickets(){ if (ticketsNum<=0){ flag = false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+"买到的票序号为:"+(ticketsNum--)); } }
-
2个人操作1个银行账户
package com.zhm.syn; public class UnsafeBank { public static void main(String[] args) { Account account = new Account(1000,"共同财产"); getMoney p1 = new getMoney(account,500,"you"); getMoney p2 = new getMoney(account,1000,"she"); p1.start(); p2.start(); } } //账户 class Account { public int accountMoney;//账户金额 public String name;//账户人 public Account(int accountMoney, String name) { this.accountMoney = accountMoney; this.name = name; } } //取钱 class getMoney extends Thread{ private Account account;//取钱账户 private int outMoney;//取钱金额 private int nowMoney;//现在有多少钱 public getMoney(Account account,int outMoney,String outName){ super(outName); this.account = account; this.outMoney = outMoney; } @Override public void run() { getMoney(); } //取钱 public void getMoney(){ if (outMoney>account.accountMoney){ System.out.println(this.getName()+"-->账户钱不够"); return; }; try { //加延时,代表两边都能取到内存的1000账户金额数据 //相当于放大安全问题,某一线程取到数据后,等待其他线程取到数据,问题更容易发生 Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } account.accountMoney = account.accountMoney - outMoney; nowMoney = nowMoney + outMoney; //Thread.currentThread().getName()=相当于=this.getName() System.out.println(this.getName()+"取钱后,"+account.name+"余额为-->"+account.accountMoney); System.out.println(this.getName()+"手里有-->"+nowMoney); } }
-
list数组
-
存储10000个线程名字到数列,数列大小小于10000,有几个线程重复存储到同一位置
package com.zhm.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++) { Thread thread = new Thread(()->{ list.add(Thread.currentThread().getName()); }); thread.start(); } Thread.sleep(3000); System.out.println(list.size()); } }
同步方法和同步块
-
同步方法 synchronized修饰符
-
public synchronized void run(){}
-
同步块 synchronized修饰符方法体内
-
synchronized(对象){},对象推荐使用共享资源
-
对谁增删改查对象就写谁
-
同步方法不用写对象,对象就是this,所以synchronized(this){}=方法加修饰符synchronized
List<String> list = new ArrayList<String>(); for (int i = 0; i < 10000; i++) { Thread thread = new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }); thread.start(); }
public synchronized void buyTickets(){ if (ticketsNum<=0){ flag = false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+"买到的票序号为:"+(ticketsNum--)); }
public void getMoney(){ synchronized (account){ if (outMoney>account.accountMoney){ System.out.println(this.getName()+"-->账户钱不够"); return; }; try { //加延时,代表两边都能取到内存的1000账户金额数据 //相当于放大安全问题,某一线程取到数据后,等待其他线程取到数据,问题更容易发生 Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } account.accountMoney = account.accountMoney - outMoney; nowMoney = nowMoney + outMoney; //Thread.currentThread().getName()=相当于=this.getName() System.out.println(this.getName()+"取钱后,"+account.name+"余额为-->"+account.accountMoney); System.out.println(this.getName()+"手里有-->"+nowMoney); } }
最后一个两人取一个账户钱的例子里,不能用同步方法,因为同步方法代表监视同步this,即GetMoney取钱这个对象,而实际增删改查的数据是account账户,所以要使用同步块
Thread thread = new Thread(()->{}); thread.start(); //= new Thread(()->{}).start; //= Runnable runnable = new Runnable(){ //重新run方法 };//匿名内部类 new Thread(runnbale).start; //= Runnable runnable = ()->{ //run方法体 }; new Thread(runnbale).start;
死锁情况
-
多个线程互相抱着对方需要的资源,然后形成僵持
-
类似两个锁分别锁着对方的钥匙
//死锁情况 synchronized (lipStick){ System.out.println(herName+"拿到镜子"); Thread.sleep(2000); synchronized (mirror){ System.out.println(herName+"拿到镜子"); } }
package com.zhm.syn; 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 choic;//标识符 String herName;//使用人的名字 public Makeup(int choic, String herName) { this.choic = choic; this.herName = herName; } @Override public void run() { try { makeup(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //化妆 private void makeup() throws InterruptedException { if (choic == 0){ synchronized (lipStick){ System.out.println(herName+"拿到口红"); Thread.sleep(2000); } synchronized (mirror){ System.out.println(herName+"拿到镜子"); } }else { synchronized (mirror){ System.out.println(herName+"拿到镜子"); Thread.sleep(3000); } synchronized (lipStick){ System.out.println(herName+"拿到口红"); } } } }
lock锁
-
类似同步块,区别是lock是显式定义锁,范围都是显式,synorized同步块是隐式锁
-
用lock.lock()和lock.unlock()方法包围监测内容
-
一般try块写lock,finally写unlock
package com.zhm.syn; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(String[] args) { LockBuyTicket thread = new LockBuyTicket(); new Thread(thread).start(); new Thread(thread).start(); } } class LockBuyTicket implements Runnable{ private final ReentrantLock lock = new ReentrantLock(); int ticketNums = 10; @Override public void run() { try { lock.lock(); while (ticketNums>0){ System.out.println(ticketNums--); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } finally { lock.unlock(); } } }
生产者消费者问题
-
管程法
-
用一个缓冲区存商品
-
生产者满了就不存,等待;不是满就存,通知停止等待
-
消费者空了就不取,等待;不是空就取,通知停止等待
-
记得使用syngorized同步方法或者同步块
package com.zhm.gaoji; //商品,生产者,消费者,缓冲区 public class TestProdCum { public static void main(String[] args) { SynContainer synContainer = new SynContainer(); Producer producer = new Producer(synContainer); Consumer consumer = new Consumer(synContainer); producer.start(); consumer.start(); } } //鸡 class Chicken{ int id;//鸡编号 public Chicken(int id) { this.id = id; } } //生产者 class Producer extends Thread{ SynContainer synContainer; public Producer(SynContainer synContainer) { this.synContainer = synContainer; } @Override public void run() { //生产100次,最后一只是99 for (int i = 0; i < 100; i++) { synContainer.push(new Chicken(i)); System.out.println("生产了第"+i+"只鸡"); } } } //消费者 class Consumer extends Thread{ SynContainer synContainer; public Consumer(SynContainer synContainer) { this.synContainer = synContainer; } @Override public void run() { for (int i = 0; i < 100; i++) { Chicken chicken = synContainer.pop(); System.out.println("消费了第"+chicken.id+"只鸡"); } } } //缓冲区,存鸡,取鸡 class SynContainer { Chicken[] chickens = new Chicken[10]; int count;//当前鸡的数量 //存鸡 public synchronized void push(Chicken chicken){ //如果鸡满了,就不存,等待 if (count == chickens.length){ try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //没满就存 chickens[count++] = chicken; //存完通知 this.notifyAll(); } //取鸡 public synchronized Chicken pop(){ //如果没鸡,就不取,等待 if (count == 0){ try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //有鸡就取 count--; Chicken chicken = chickens[count]; //取完通知 this.notifyAll(); return chicken; } }
-
信号灯法
-
用一个标志位flag分开
-
例如flag=t,消费者等待,生产者执行,执行完通知,flag取反
package com.zhm.gaoji; public class TestProdCun02 { public static void main(String[] args) { TV tv = new TV(); new Player(tv).start(); new Watcher(tv).start(); } } //信号灯法, //标志位T代表演员演出,观众等待 //标志位F代表演员等待,观众演出 //演员 class Player extends Thread{ TV tv; public Player(TV tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 10; i++) { if (i % 2 == 0){ this.tv.play("快乐大本营"); }else this.tv.play("天天向上"); } } } //观众 class Watcher extends Thread{ TV tv; public Watcher(TV tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 10; i++) { tv.watch(); } } } //节目 class TV{ boolean flag = true; String tvName = "begin"; public synchronized void play(String tvName){ //flag为F,演员等待 if (!flag){ try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //否则演员开始演 System.out.println(tvName+"演出开始"); //通知等待的开始 this.notifyAll(); this.tvName = tvName; flag = !flag; } public synchronized void watch(){ //flag为T,观众等待 if (flag){ try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //否则观众开始看 System.out.println("观众开始看"+this.tvName); //通知 this.notifyAll(); flag = !flag; } }
线程池
-
创建有大小的线程池子,放入线程,需要就取出,优化效率
package com.zhm.gaoji; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestPool { public static void main(String[] args) { //创建服务,创建线程池子 ExecutorService service = Executors.newFixedThreadPool(10); //执行 service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //关闭服务 service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }