多线程

103 阅读9分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

基础入门

1.核心概念

  • 线程就是独立的执行路径;
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的;
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 线程会带来额外的开销,如CPU调度时间,并发控制开销;
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

2.代码演示

 public class TestThread1 extends Thread {
 ​
     public void run(){
         for (int i = 0; i < 20; i++) {
             // run方法线程体
             System.out.println("我在看代码-----" + i);
         }
     }
 ​
     public static void main(String[] args) {
         // main线程,主线程
 ​
         // 创建一个线程对象
         TestThread1 testThread1 = new TestThread1();
         // 调用run()方法开启线程
         testThread1.run();
         // 调用start()方法开启线程
         testThread1.start();
 ​
 ​
         for (int i = 0; i < 1000; i++) {
             System.out.println("我在学习多线程-----" + i);
         }
 ​
     }
 }

image-20220213094816867.png

多线程同步下载网络图片

 // 练习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() {
         WebDownLoader webDownLoader = new WebDownLoader();
         webDownLoader.downLoader(url,name);
         System.out.println("下载了文件名为:" + name);
     }
 ​
     public static void main(String[] args) {
         TestThread2 t1 = new TestThread2("https://img.alicdn.com/imgextra/i4/6000000001102/O1CN01HJ1Qxo1K0lCQcyutq_!!6000000001102-0-octopus.jpg","1.jpg");
         TestThread2 t2 = new TestThread2("https://gtms02.alicdn.com/tps/i2/TB10vPXKpXXXXacXXXXvKyzTVXX-520-280.jpg","2.jpg");
         TestThread2 t3 = new TestThread2("https://gtms03.alicdn.com/tps/i3/TB1gXd1JXXXXXapXpXXvKyzTVXX-520-280.jpg","3.jpg");
 ​
         t1.start();
         t2.start();
         t3.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异常,downLoader方法出现问题");
         }
     }
 }

结论:线程不一定立即执行,由CPU进行调度

实现Runnable接口

 // 创建线程2: 实现Runnable接口,重写run()方法,执行线程需要丢入的runnable接口实现类,调用start()方法。
 public class TestThread3 implements Runnable {
     @Override
     public void run() {
         for (int i = 0; i < 100; i++) {
             // run方法线程体
             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 < 1000; i++) {
             System.out.println("我在学习多线程-----" + i);
         }
     }
 }

小结

  • 继承Threa类

    • 子类继承Thread类具备多线程能力
    • 启动线程:子类对象.start()
    • 不建议使用:避免OOP单继承局限性
  • 实现Runnable接口

    • 实现接口Runnable具有多线程能力
    • 启动线程:传入目标对象Thread对象.start()
    • 推荐使用:避免单继承局限性,灵活方便,方便统一个对象被多个线程使用

初识并发问题

 // 多个线程同时操作同一个对象
 // 买火车票的例子
 ​
 // 发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
 public class TestThread4 implements Runnable {
     private int ticketNum = 10;
     @Override
     public void run() {
         while (true){
             if (ticketNum <= 0){
                 break;
             }
             // 模拟延时
             try {
                 Thread.sleep(200);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             System.out.println(Thread.currentThread().getName() + "--->拿到了第" + ticketNum-- + "票");
         }
     }
 ​
     public static void main(String[] args) {
         TestThread4 testThread4 = new TestThread4();
 ​
         new Thread(testThread4,"小明").start();
         new Thread(testThread4,"小红").start();
         new Thread(testThread4,"黄牛").start();
     }
 }

结果如下

 黄牛--->拿到了第9票
 小明--->拿到了第8票
 小红--->拿到了第10票
 小红--->拿到了第7票
 小明--->拿到了第5票
 黄牛--->拿到了第6票
 黄牛--->拿到了第4票
 小明--->拿到了第4票
 小红--->拿到了第4票
 黄牛--->拿到了第3票
 小明--->拿到了第3票
 小红--->拿到了第2票
 黄牛--->拿到了第1票
 小红--->拿到了第1票
 小明--->拿到了第1票

龟兔赛跑

image-20220214084724920.png

 // 模拟龟兔赛跑
 public class Race implements Runnable {
     private static String winner;
     @Override
     public void run() {
         for (int i = 0; i <= 1000; i++) {
             // 模拟兔子睡觉
 //            if (Thread.currentThread().getName().equals("兔子")&&i%400==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 >= 1000){
                 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();
     }
 }

静态代理模式

 // 静态代理模式
 /*
 *真实对象和代理对象都要实现同一个接口
 * 代理对象要代理真实角色
 * */
 // 好处:
 // 代理对象可以做很多真实对象做不了的事情
 // 真实对象专注做自己的事情
 ​
 public class StaticProxy {
     public static void main(String[] args) {
         You you = new You();
         you.HappyMarry();
         System.out.println("===================");
         WeddingCompany weddingCompany = new WeddingCompany(new You());
         weddingCompany.HappyMarry();
     }
 ​
 }
 ​
 interface Marry{
     void HappyMarry();
 }
 ​
 class You implements Marry{
     // 真实角色
     @Override
     public void HappyMarry() {
         System.out.println("HappyMarry");
     }
 }
 ​
 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("结束,收尾款");
     }
 }

Lamda表达式

 /*
 推导Lambda表达式
  */
 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");
     }
 }

练习

 public class TestLambda2 {
 ​
     static class Love2 implements ILove{
         @Override
         public void Love(int a) {
             System.out.println("I Love You--->"+a);
         }
     }
     public static void main(String[] args) {
         ILove love = new Love();
         love.Love(2);
 ​
         love = new Love2();
         love.Love(3);
 ​
         class Love3 implements ILove{
             @Override
             public void Love(int a) {
                 System.out.println("I Love You--->"+a);
             }
         }
         love = new Love3();
         love.Love(4);
 ​
         love = new ILove() {
             @Override
             public void Love(int a) {
                 System.out.println("I Love You--->"+a);
             }
         };
         love.Love(5);
 ​
         love = (int a) -> {
                 System.out.println("I Love You--->"+a);
         };
         love.Love(7);
 ​
         // 简化1
         love = (a) -> {
             System.out.println("I Love You--->"+a);
         };
         love.Love(8);
 ​
         // 简化2:去掉括号
         love = a -> {
             System.out.println("I Love You--->"+a);
         };
         love.Love(9);
 ​
         // 简化3:去掉花括号
         love = a ->
             System.out.println("I Love You--->"+a);
 ​
         love.Love(10);
 ​
         // 总结:
             // lambda 表达式只能有一行代码的情况下才能简化成一行,如果有多行,那么就用代码块包裹。
             // 前提是必须是函数式接口(函数式接口:接口中只有一个方法)
         // 多个参数也可以去掉参数类型,要去掉就都去掉,必须加括号
     }
 }
 ​
 interface ILove{
     void Love(int a);
 }
 ​
 class Love implements ILove{
     @Override
     public void Love(int a) {
         System.out.println("I Love You--->"+a);
     }
 }

线程状态

image-20220216105833677.png

线程停止

 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){
                 testStop.stop();
                 System.out.println("线程该停止了");
             }
         }
     }
 }

线程休眠_Sleep

  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep存在异常InterruptedException;
  • sleep时间达到后线程进入就绪状态;
  • sleep可以模拟网络延时,倒计时等;
  • 每一个对象都有一个锁,sleep不会释放锁。

为什么需要网络延时?

答:放大问题的发生性

模拟倒计时

 // 模拟倒计时
 public class TestSleep2 {
 ​
     public static void main(String[] args) throws InterruptedException {
 //        tenDown(); //倒计时方式调用
         // 打印系统当前时间
         Date date = new Date(System.currentTimeMillis());
         int i = 10;
         while (i>=0){
             Thread.sleep(1000);
             System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
             date = new Date(System.currentTimeMillis());
             i--;
 ​
         }
     }
 ​
     public static void tenDown() throws InterruptedException {
         int num = 10;
         while (num>=0){
             Thread.sleep(1000);
             System.out.println(num--);
 ​
         }
     }
 }

线程礼让

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞;
  • 将线程从运行状态转为就绪状态;
  • 让cpu重新调度,礼让不一定成功,看cpu心情

代码演示

 // 线程礼让
 // 礼让不一定成功,看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方法(类似插队)

代码演示

 // 测试join方法,想象为插队
 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) throws InterruptedException {
         // vip线程  启动
         TestJoin testJoin = new TestJoin();
         Thread thread = new Thread(testJoin);
 ​
 ​
         for (int i = 0; i < 1000; i++) {
             if (i==200){
                 thread.start();
                 // vip线程插队
                 thread.join();
             }
 ​
             // 执行主线程
             System.out.println("main"+i);
         }
     }
 }

代码截图

image-20220219143239207.png

image-20220219143256203.png

观测线程状态

 // 观察测试线程的状态
 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()调度之前先设置优先级

 // 测试线程优先级
 public class TestPriority {
     public static void main(String[] args) {
         // 主线程有默认的优先级
         System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); //main主线程
 ​
         MyPriority myPriority = new MyPriority();
 ​
         Thread t1 = new Thread(myPriority,"1");
         Thread t2 = new Thread(myPriority,"2");
         Thread t3 = new Thread(myPriority,"3");
         Thread t4 = new Thread(myPriority,"4");
         Thread t5 = new Thread(myPriority,"5");
         Thread t6 = new Thread(myPriority,"6");
 ​
         // 不设置优先级 
         t1.start(); // 默认优先级---5
 ​
         t2.setPriority(2);
         t2.start();
 ​
         t3.setPriority(4);
         t3.start();
 ​
         t4.setPriority(6);
         t4.start();
 ​
         t5.setPriority(Thread.MAX_PRIORITY);
         t5.start();
 ​
         t6.setPriority(Thread.MIN_PRIORITY);
         t6.start();
     }
 }
 ​
 class MyPriority implements Runnable {
     @Override
     public void run() {
         System.out.println("Thread"+Thread.currentThread().getName() + "--->" + Thread.currentThread().getPriority());
     }
 }

image-20220220100421382.png

结论:默认优先级一直优先,执行的顺序不一定按照优先级来运行。

守护(daemon)线程

  • 线程分为用户线程守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如:后台记录操作日志,监控内存,垃圾回收等待...
 // 测试守护线程
 // 上帝守护你
 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();
 ​
         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!============");
     }
 }

三大不安全案例

队列+锁能解决这个问题

不安全买票案例

 // 可能出现负数
 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 ticketNum = 10;
     boolean flag = true;
 ​
     @Override
     public void run() {
         // 买票
         while (flag){
             try {
                 buy();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
     private void buy() throws InterruptedException {
         // 判断是否有票
         if (ticketNum<=0){
             flag = false;
             return;
         }
         // 模拟延时
         Thread.sleep(100);
         // 买票
         System.out.println(Thread.currentThread().getName()+"买到了第"+ticketNum--+"票");
     }
 }

不安全银行取钱案例

 public class UnSafeBank {
     public static void main(String[] args) {
         Account account = new Account(100,"结婚基金");
         Drawing you = new Drawing(account,50,"你");
         Drawing girl = new Drawing(account,100,"girl");
 ​
         you.start();
         girl.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() {
         // 判断有没有钱
         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);
         // this.name = Thread.currentThread().getName()
         System.out.println(this.getName()+"手里的钱:"+nowMoney);
 ​
     }
 }

线程不安全集合

 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(()->{
                 list.add(Thread.currentThread().getName());
             }).start();
         }
         // 延时
         Thread.sleep(300);
         System.out.println(list.size());
     }
 }

锁(syn)

解决第15小节中不安全线程的方法

不安全买票案例

 // synchronized 同步方法,锁的是this
 private synchronized void buy(){
     // 判断是否有票
     if (ticketNum<=0){
         flag = false;
         return;
     }
     // 买票
     System.out.println(Thread.currentThread().getName()+"买到了第"+ticketNum--+"票");
 }

不安全银行取钱案例

 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);
         // this.name = Thread.currentThread().getName()
         System.out.println(this.getName()+"手里的钱:"+nowMoney);
     }
 }

线程不安全集合

 new Thread(()->{
     // 锁住(同步块)
     synchronized (list){
         list.add(Thread.currentThread().getName());
     }
 }).start();

死锁

死锁前

 public class DeadLock {
     public static void main(String[] args) {
         MakeUp m1 = new MakeUp(0,"灰姑娘");
         MakeUp m2 = new MakeUp(1,"白雪公主");
 ​
         m1.start();
         m2.start();
     }
 }
 ​
 // 口红
 class Lipstick{
 ​
 }
 ​
 // 镜子
 class Mirror{
 ​
 }
 ​
 // 化妆
 class MakeUp extends Thread{
     // 需要的资源只有一份,用static来保证只有一份
     static Lipstick lipstick = new Lipstick();
     static Mirror mirror = new Mirror();
 ​
     int choice; // 选择
     String name; // 使用化妆品的人
     public MakeUp(int choice, String name) {
         this.choice = choice;
         this.name = name;
     }
 ​
     @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.name+"获得口红的锁"); //一秒后想获得镜子
                 Thread.sleep(1000);
                 synchronized (mirror){// 获得镜子
                 System.out.println(this.name+"获得镜子的锁");
                 }
             }
         }else {
             synchronized (mirror){ // 获得镜子的锁
                 System.out.println(this.name+"获得镜子的锁"); // 两秒后想获得口红
                 Thread.sleep(2000);
                 synchronized (lipstick){
                 System.out.println(this.name+"获得口红的锁");
                 }
             }
  
         }
     }
 }

解决死锁后

 public class DeadLock {
     public static void main(String[] args) {
         MakeUp m1 = new MakeUp(0,"灰姑娘");
         MakeUp m2 = new MakeUp(1,"白雪公主");
 ​
         m1.start();
         m2.start();
     }
 }
 ​
 // 口红
 class Lipstick{
 ​
 }
 ​
 // 镜子
 class Mirror{
 ​
 }
 ​
 // 化妆
 class MakeUp extends Thread{
     // 需要的资源只有一份,用static来保证只有一份
     static Lipstick lipstick = new Lipstick();
     static Mirror mirror = new Mirror();
 ​
     int choice; // 选择
     String name; // 使用化妆品的人
     public MakeUp(int choice, String name) {
         this.choice = choice;
         this.name = name;
     }
 ​
     @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.name+"获得口红的锁"); //一秒后想获得镜子
                 Thread.sleep(1000);
             }
             synchronized (mirror){// 获得镜子
                 System.out.println(this.name+"获得镜子的锁");
             }
         }else {
             synchronized (mirror){ // 获得镜子的锁
                 System.out.println(this.name+"获得镜子的锁"); // 两秒后想获得口红
                 Thread.sleep(2000);
             }
             synchronized (lipstick){
                 System.out.println(this.name+"获得口红的锁");
             }
         }
     }
 }

Lock锁(ReentrantLock)

 public class TestReentrantLock{
     public static void main(String[] args) {
         Lock2 lock2 = new Lock2();
 ​
         new Thread(lock2).start();
         new Thread(lock2).start();
         new Thread(lock2).start();
     }
 }
 ​
 class Lock2 implements Runnable{
     int num = 10;
     // 定义锁
     private final ReentrantLock lock = new ReentrantLock();
     @Override
     public void run() {
         while (true){
             try {
                 lock.lock();// 加锁
                 if (num>0){
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println(num--);
                 }else {
                     break;
                 }
             }finally {
                 lock.unlock();// 解锁
             }
 ​
         }
     }
 }

ReentrantLock锁相比于synchronized在jvm里面消耗更少,所以更推荐使用ReentrantLock。

生产者消费者

 // 测试生产者消费者模型
 // 生产者,消费者,产品,缓冲区
 public class TestPC {
     public static void main(String[] args) {
         SynContainer synContainer = new SynContainer();
         new Producer(synContainer).start();
         new Customer(synContainer).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+"只鸡");
             try {
                 container.push(new Chicken(i));
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }
 ​
 // 消费者
 class Customer extends Thread{
     SynContainer container;
     public Customer(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;
         count++;
         // 可以通知消费者了
         this.notifyAll();
     }
 ​
     // 消费者消费
     public synchronized Chicken pop() throws InterruptedException {
         // 如果缓冲区为空
         if (count == 0){
             this.wait();
         }
         // 如果缓冲区有产品则可以取出产品
         count--;
         Chicken chicken = chickens[count];
         // 吃完了,通知生产
         this.notifyAll();
         return chicken;
     }
 }

线程池

代码如下

 public class TestPool {
     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());
 ​
         // 关闭连接
         service.shutdown();
     }
 }
 ​
 class MyThread implements Runnable{
     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName());
     }
 }