多线程--技术总结

一、 线程核心概念

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

二、创建方式(三种

  1. 继承Thread类(重点)

    TestThread01

    package com.kuang.demo01;
    
    /**
     * 创建线程方式一:
     * 继承Thread类
     * 重写run()方法
     * 调用start开启线程
     */
    public class TestThread01 extends Thread {
    
        @Override
        public void run() {
          //run方法线程体
            for (int i = 0; i <200 ; i++) {
                System.out.println("我在看代码--"+i);
            }
        }
        //main线程,主线程
        public static void main(String[] args) {
            //创建一个线程对象
            TestThread01 testThread01 = new TestThread01();
            //调用start()方法开启线程
            //testThread01.start();
            testThread01.run();
            for (int i = 0; i <200 ; i++) {
                System.out.println("我在学习多线程"+i);
            }
        }
    
    
    
    }
    

    TestThread02

    测试之前先去下载

    把包下的commons-io-2.9.0.jar复制到项目的lib目录下(手动添加一个lib包),之后选中lib,右键>Add as Library,就可以了

    package com.kuang.demo01;
    
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    
    /**
     * 练习Thread
     * 实现多线程同步下载图片
     */
    public class TestThread02 extends Thread {
        private String url;//网络图片地址
        private String name;//保存的文件名
        public TestThread02(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) {
            TestThread02 t1 = new TestThread02("https://img2.baidu.com/it/u=887918930,2064725991&fm=26&fmt=auto&gp=0.jpg","张天爱1.jpg");
            TestThread02 t2 = new TestThread02("https://img2.baidu.com/it/u=3810345217,1257588557&fm=26&fmt=auto&gp=0.jpg","张天爱2.jpg");
            TestThread02 t3 = new TestThread02("https://img0.baidu.com/it/u=2867474920,409094384&fm=26&fmt=auto&gp=0.jpg","张天爱3.jpg");
            //启动线程
            t1.start();
            t2.start();
            t3.start();
        }
    }
    //下载器
    class WebDownLoader{
        //下载方法
        public  void downLoader(String url,String name){
            //引入FileUtils工具类
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downLoader方法出现问题!");
            }
        }
    }
    
  2. 实现Runnable接口(重点)

    package com.kuang.demo01;
    
    import org.apache.commons.io.FileUtils;
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    
    /**
     * 联系Thread
     * 实现多线程同步下载图片
     */
    public class TestThread02 implements Runnable {
        private String url;//网络图片地址
        private String name;//保存的文件名
    
        public TestThread02(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) {
            TestThread02 t1 = new TestThread02("https://img2.baidu.com/it/u=887918930,2064725991&fm=26&fmt=auto&gp=0.jpg","张天爱1.jpg");
            TestThread02 t2 = new TestThread02("https://img2.baidu.com/it/u=3810345217,1257588557&fm=26&fmt=auto&gp=0.jpg","张天爱2.jpg");
            TestThread02 t3 = new TestThread02("https://img0.baidu.com/it/u=2867474920,409094384&fm=26&fmt=auto&gp=0.jpg","张天爱3.jpg");
            //启动线程
            new Thread(t1).start();
            new Thread(t2).start();
            new Thread(t3).start();
        }
    }
    //下载器
    class WebDownLoader{
        //下载方法
        public  void downLoader(String url,String name){
            //引入FileUtils工具类
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downLoader方法出现问题!");
            }
        }
    }
    

    龟兔赛跑

    package com.kuang.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(100);
                    } 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);
                    return true;
                }
            }
            return false;
        }
    
    
        public static void main(String[] args) {
            Race race = new Race();
            new Thread(race,"兔子").start();
            new Thread(race,"乌龟").start();
        }
    }
    
    
  3. 实现Callable接口(了解)

    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() {
           WebDownLoader webDownLoader = new WebDownLoader();
            webDownLoader.downLoader(url,name);
            System.out.println("下载了文件名为:"+name+"的文件");
            return true;
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            TestCallable t1 = new TestCallable("https://img2.baidu.com/it/u=887918930,2064725991&fm=26&fmt=auto&gp=0.jpg","张天爱1.jpg");
            TestCallable t2 = new TestCallable("https://img2.baidu.com/it/u=3810345217,1257588557&fm=26&fmt=auto&gp=0.jpg","张天爱2.jpg");
            TestCallable t3 = new TestCallable("https://img0.baidu.com/it/u=2867474920,409094384&fm=26&fmt=auto&gp=0.jpg","张天爱3.jpg");
            //创建执行服务
            ExecutorService ser = Executors.newFixedThreadPool(3);
            //提交执行
            Future<Boolean> r1 = ser.submit(t1);
            Future<Boolean> r2 = ser.submit(t2);
            Future<Boolean> r3 = ser.submit(t3);
            //获取结果
            Boolean rs1 = r1.get();
            Boolean rs2 = r2.get();
            Boolean rs3 = r3.get();
            System.out.println(rs1);
            System.out.println(rs2);
            System.out.println(rs3);
            //关闭服务
            ser.shutdownNow();
    
        }
    }
    
    //下载器
    class WebDownLoader{
        //下载方法
        public  void downLoader(String url,String name){
            //引入FileUtils工具类
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downLoader方法出现问题!");
            }
        }
    }
    

三、静态代理模式

  1. 举例

    package com.kuang.staticProxy;
    
    /**
     * 静态代理模式总结:
     * 真实对象和代理对象都要实现同一个接口
     * 代理对象要代理真实角色
     *
     * 好处:
     * 代理对象可以做很多真实对象做不了的事情
     * 真实对象专注做自己的事情
     */
    public class StaticProxy {
    
        public static void main(String[] args) {
            You you = new You();//你要结婚
    
            new Thread(()-> System.out.println("我爱你")).start();//thread方法类似以下的代理模式
    
            new WeddingCompany(new You()).HappyMarry();//自己写的代理模式
    
        }
    }
    
    interface Marry{
    
        /**
         * 人间四大喜事
         * 1.金榜题名时
         * 2.他乡遇故知
         * 3.久旱逢甘霖
         * 4.洞房花烛夜
         */
        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("结婚之后,收款");
        }
    
    
    }
    

四、Lambda表达式

  1. Test1:

    package com.kuang.lambda;
    
    /**
     * 推导lambda表达式
     */
    public class TestLambda01 {
    
        //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");
        }
    }
    
  2. Test2

    package com.kuang.lambda;
    
    public class TestLambda02 {
        public static void main(String[] args) {
            Ilove love=null;
            //1.lambda表达式简化
          /*   love = (int a,int b)->{
                System.out.println("我爱你-->"+a);
            };*/
            //简化1:参数类型
            /*love = (a,b)->{
                System.out.println("我爱你-->"+a);
            };*/
            //简化3:去掉花括号
            /*love=a->System.out.println("我爱你-->"+a);*/
    
            //简化2:简化括号
            love = (a,b)->{
                System.out.println("我爱你-->"+a);
                System.out.println("我爱你-->"+b);
            };
            love.love(521,520);
            /**
             * 总结:
             * lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,就用代码块包裹
             * 前提是接口必须是函数式接口(只有一个方法的接口)
             * 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
             */
        }
    }
    
    interface Ilove{
        void love(int a,int b);
    }
    
    
    

五、线程状态

new-->就绪-->运行-->阻塞-->dead

线程一旦进入死亡状态,就不能再次启动了

  1. 线程停止

    package com.kuang.status;
    
    /**
     * 线程停止
     * 1.建议线程正常停止--利用次数,不建议死循环
     * 2.建议使用标志位--设置一个标志位
     * 3.不要使用stop、destroy等过时或者JDK不建议使用的方法
     */
    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("线程停止了");
                }
            }
        }
    }
    
    
  2. 线程休眠

    1. Test1--模拟网络延时

      package com.kuang.status;
      
      /**
       * 模拟网络延时:放大问题的发生性
       * 每一个对象都有一把锁,sleep不会释放锁
       */
      public class TestSleep implements Runnable {
          //票数
          private int ticketNums=10;
      
          @Override
          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) {
              TestSleep ticket = new TestSleep();
      
              new Thread(ticket,"貂蝉").start();
              new Thread(ticket,"吕布").start();
              new Thread(ticket,"小乔").start();
          }
      }
      
      
    2. Test2--模拟倒计时

      package com.kuang.status;
      
      import java.text.SimpleDateFormat;
      import java.util.Date;
      /**
       * 模拟倒计时
       */
      public class TestSleep02 {
          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();
                  }
              }
          }
          //模拟倒计时
          public static void tenDown() throws InterruptedException {
              int num=20;
              while (true){
                      Thread.sleep(1000);
                  System.out.println(num--);
                  if (num<=0){
                      break;
                  }
              }
          }
      }
      
      
  3. 线程礼让

    1. 礼让不一定成功,看CPU心情

      package com.kuang.status;
      
      /**
       * 线程礼让
       * 礼让不一定成功,看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()+"线程停止执行");
          }
      }
      
      
  4. 观察测试线程的状态

    1. 测试

      package com.kuang.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(100);
                  state=thread.getState();//更新线程状态
                  System.out.println(state);
              }
      
          }
      }
      
      

六、线程优先级

  1. ​ 测试

    1. 测试代码

      package com.kuang.state;
      
      /**
       * 线程优先级
       */
      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);
              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);//最大==10
              t4.start();
      
              t5.setPriority(8);
              t5.start();
      
              t6.setPriority(7);
              t6.start();
          }
      }
      
      class MyPriority implements Runnable{
          @Override
          public void run() {
              System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
          }
      }
      

七、守护线程

  1. 测试

    1. 测试代码

      package com.kuang.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("=========再见,这个世界======================!");
          }
      }
      

八、线程同步(重点

  1. 举例

    1. 买票

      package com.kuang.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();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      
      
          private synchronized void buy() throws InterruptedException {
              //判断是否有票
              if (ticketNums<=0){
                  flag=false;
                  return;
              }
              Thread.sleep(1000);
              System.out.println(Thread.currentThread
                                 ().getName()+"拿到"+ticketNums--);
          }
      }
      
    2. 取钱

      package com.kuang.syn;
      
      /**
       * 不安全的取钱
       * 两个人去银行取钱
       */
      public class UnSafeBank {
      
          public static void main(String[] args) {
              //账户
              Account account = new Account(1000,"买车资金");
              //你
              Drawing you = new Drawing(account,50,"你");
              //girlFriend
              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;
          }
      
      //取钱
          //synchronized,默认锁的是this.
          @Override
          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);
                  System.out.println(this.getName()+"手里的钱:"+nowMoney);
              }
      
      
      
          }
      }
      
      
      
      //
      
    3. 集合

      package com.kuang.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(3000);
              System.out.println(list.size());
          }
      }
      
      
    4. 测试JUC安全类型的集合

      package com.kuang.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());
          }
      
      }
      
      
  2. 死锁

    1. 产生死锁的四个必要条件

    2. 测试代码:

      package com.kuang.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(2000);
                  }
                  synchronized (lipstick){//2秒后想获得口红
                      System.out.println(this.girlName+"获得口红的锁");
                  }
              }
          }
      }
      
  3. Lock锁

    1. 测试代码

      package com.kuang.gaoji;
      
      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 final 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();
                  }
              }
          }
      }
      
  4. 并发协作模型“生产者/消费者模式”----管程法

    1. 举例:

      package com.kuang.gaoji;
      
      /**
       * 测试:生产者消费者模型:-->利用缓冲区解决:管程法
       *
       * 生产者、消费者、产品、缓冲区
       */
      public class TestPC {
      
          public static void main(String[] args) {
              SynContainer synContainer = new SynContainer();
              new Productor(synContainer).start();
              new Consumer(synContainer).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++) {
                  container.push(new Chicken(i));
                  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++) {
                  System.out.println("消费了-->"+container.pop().id+"只鸡");
              }
          }
      }
      
      //产品
      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){
              //如果容器满了,就需要等待消费者去消费
              if (count==chickens.length){
                 //通知消费者消费,生产者等待
                  try {
                      this.wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              //如果没满,就需要丢入产品
              chickens[count]=chicken;
              count++;
              //可以通知消费者消费
              this.notifyAll();
          }
      
          //消费者消费产品
          public synchronized Chicken pop(){
              //判断能否消费
              if (count==0){
                  //等待生产者生产,消费者等待
                  try {
                      this.wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              //如果可以消费
              count--;
             Chicken chicken= chickens[count];
             //吃完了,通知生产者生产
              this.notifyAll();
              return chicken;
          }
      }
      
  5. 并发协作模型“生产者/消费者模式”----信号灯法

    1. 举例

      package com.kuang.gaoji;
      
      /**
       * 测试:生产者消费者模型:-->利用缓冲区解决:信号灯法--标志位解决
       */
      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){
                      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 < 20; i++) {
                  this.tv.watch();
              }
          }
      }
      //产品--节目
      class TV{
          //演员表演,观众等待--true
          //观众观看,演员等待--false
          String voice;//表演的节目
          boolean flag=true;
          //表演
          public  synchronized void play(String voice){
              if (!flag){
                  try {
                      this.wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              System.out.println("演员表演了:"+voice);
              //通知观众观看
              this.notifyAll();//通知唤醒
              this.voice=voice;
              this.flag=!this.flag;
          }
      
          //观看
          public  synchronized  void watch(){
              if (flag){
                  try {
                      this.wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              System.out.println("观众观看了:"+voice);
              //通知演员表演
              this.notifyAll();
              this.flag=!this.flag;
          }
      }
      

九、线程池

  1. package com.kuang.gaoji;
    
    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);
    
            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() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+i);
            }
        }
    }
    

十、总结

package com.kuang.gaoji;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 线程的总结
 */
public class ThreadNew {
    public static void main(String[] args) {

      		  //启动线程1
        new MyThread1().start();
            //启动线程2
        new Thread(new MyThread2()).start();
 		  //启动线程3
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();
        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}
//1.继承Thread类
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}
//2.实现Runnable接口
class MyThread2 implements Runnable{

    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}
//3.实现Callable接口
class MyThread3 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}
posted @ 2021-06-07 16:59  青喺半掩眉砂  阅读(44)  评论(2编辑  收藏  举报