多线程学习

1. 线程

  • 线程开始需要 new Thread(对象,“名字”).start
  • 其他需要用到Thread的地方不需要new
    • 启动线程需要new Thread
    • Thread调用方法不需要new
  • 重写的Run方法是线程,线程内放执行的操作

2. 继承Thread类:

  • 子类继承Thread类具备多线程能力
  • 启动线程:子类对象. start()
  • 不建议使用:避免OOP单继承局限性
  • 无参
  package com.xiaojia;
  
  public class Demo01 extends Thread{
      public static void main(String[] args) {
          
          new Demo01().start();
          /*
          此段代码要写在main方法的输出语句的前面
          否则会出现main方法中的 我在看代码--> 输出完才开始输出我在学习多线程-->的情况
           */
          
          for (int i = 0; i < 500; i++) {
              System.out.println("我在看代码-->"+i);
          }
      }
  
      @Override
      public void run() {
          for (int i = 0; i < 500; i++) {
              System.out.println("我在学习多线程-->"+i);
          }
      }
  }
  • 有参
  package com.xiaojia;
  
  import org.apache.commons.io.FileUtils;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.URL;
  
  public class Demo01 extends Thread{
      public static void main(String[] args) {
          new Demo01("https://tse1-mm.cn.bing.net/th/id/OIP.5xQ4rsV36HO6J5zA4CP0QAHaNK?w=179&h=319&c=7&o=5&pid=1.7", "1.jpg").start();;
          new Demo01("https://tse2-mm.cn.bing.net/th/id/OIP.V42xnW-bEEPFVt3JZSt3hAHaNJ?w=179&h=319&c=7&o=5&pid=1.7", "2.jpg").start();;
          new Demo01("https://tse2-mm.cn.bing.net/th/id/OIP.6nX818sT5um1if-WaNxQsAHaNK?w=179&h=319&c=7&o=5&pid=1.7", "3.jpg").start();;
      }
  
      private String url;
      private String name;
  
      public Demo01(String url,String name){
          this.url = url;
          this.name = name;
          /*
          使用this的时候,这个方法外要有定义的属性,不然会出现错误
          */
      }
  
      @Override
      public void run() {
         new WebDownLoader().downloader(url,name);
          System.out.println("下载了图片"+name);
      }
  }
  class WebDownLoader{
      public void downloader(String url,String name) {
          try {
              FileUtils.copyURLToFile(new URL(url),new File(name));
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  }

3. 实现Runnable接口

  • 实现接口runnable具备多线程能力
  • 启动线程:输入目标对象+Thread对象. start()
    • new Thread(testStop).start();
  • 推荐使用:灵活方便,方便同一个对象被多个线程使用
  package com.xiaojia;
  
  public class Demo01 implements Runnable{
      public static void main(String[] args) {
  
          new Thread(new Demo01()).start();
          /*
          Runnable接口,开启线程时Thread内需要参数
          */
          for (int i = 0; i < 500; i++) {
              System.out.println("我在看代码-->"+i);
          }
      }
  
      @Override
      public void run() {
          for (int i = 0; i < 500; i++) {
              System.out.println("我在学习多线程"+i);
          }
      }
  }

4. 注意点

  • 如果线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
  public class Test implements Runnable{
             @Override
            public void run() {
                int i = 0;
                while (flag){
                    System.out.println("run....Thread"+i++);
                }
            }
            public static void main(String[] args) {
                Test testp = new Test();
                new Thread(test).start();
            }
        }
        //独立的,没有调用run方法,不执行任何操作
  • 并不是一启动线程(调用start()方法)就执行这个线程,而是进入就绪状态,什么时候运行要看CUP。

5. 线程睡眠

  • 每一个对象都有一把锁,sleep不会释放锁;
  • 模拟延时,放大事情的发生性

6. 线程礼让

  • 让CPU重新调度,礼让不一定成功,看CPU心情
  package com.xiaojia;
  
  public class Demo01 implements Runnable{
      public static void main(String[] args) {
          Demo01 demo01 = new Demo01();
          new Thread(demo01,"a").start();
          new Thread(demo01,"b").start();
      }
  
      @Override
      public void run() {
          System.out.println(Thread.currentThread().getName()+"线程开始执行");
          Thread.yield();
          System.out.println(Thread.currentThread().getName()+"线程结束执行");
      }
  }

7. 线程状态

  • start(),join(),以及get/set相当于方法调用,需要new Thread,即Thread的对象thread
  • sleep,yield,State以及其他则不需要new Thread,直接 Thread.sleep即可
  • 线程被中断或者结束就不能再次启动
  • NEW
    至今尚未启动的线程
  • RUNNABLE
    正在 Java 虚拟机中执行的线程
  • BLOCKED
    被阻塞等待监视器锁定的线程
  • WAITING
    正在等待另一个线程执行特定动作的线程
  • TIMED_WAITING
    正在等待另一个线程执行动作达到指定等待时间的操作的线程
  • TERMINATED
    已退出的线程

8. 线程优先级

  • getPriority(),setpriority(int xxx)
  • 线程优先级用数字表示,范围1-10
  • 优先级低表示被调度的几率低,先调度谁看CPU心情
  • 优先级设置在start()前使用
  • 主线程默认优先级为5,不能改变
  package com.xiaojia;
  
  public class Demo01{
      public static void main(String[] args) {
          MyPriority myPriority = new MyPriority();
          Thread thread1 = new Thread(myPriority);
          Thread thread2 = new Thread(myPriority);
          Thread thread3 = new Thread(myPriority);
          Thread thread4 = new Thread(myPriority);
          Thread thread5 = new Thread(myPriority);
          Thread thread6 = new Thread(myPriority);
  
          thread1.setPriority(Thread.MIN_PRIORITY);
          thread1.start();//Thread-0-->1
          thread2.setPriority(3);
          thread2.start();//Thread-1-->3
          thread3.start();//Thread-2-->5
          thread4.setPriority(Thread.NORM_PRIORITY);
          thread4.start();//Thread-3-->5
          thread5.setPriority(7);
          thread5.start();//Thread-4-->7
          thread6.setPriority(Thread.MAX_PRIORITY);
          thread6.start();//Thread-5-->10
      }
  }
  
  class MyPriority implements Runnable{
      @Override
      public void run() {
          System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
      }
  }

9. 守护线程

  • daemon
  • thread.setDaemon(true);
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  package com.xiaojia;
  
  public class Demo01{
      public static void main(String[] args) {
          God god = new God();
          You you = new You();
          Thread thread = new Thread(god);
          thread.setDaemon(true);
          /*
          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("你一生都开心的活着-->"+i);
          }
          System.out.println("=====GoodBye,World=====");
      }
  }

10. lambda表达式

语法

  • lamb的类型是一个接口,lambda表达式的本身就是一个接口的实现

  1. (params) -> expression[表达式]
  2. (params) -> statement[语句]
  3. (params) -> {statements}
  4. a -> System.out.println(“I like lambda -->”+ a)
  5. new Thread(() -> System.out.println(“多线程学习”)).start();
    • 函数式接口:
    • 接口只有一个方法
  • 避免匿名内部类定义过多
    • 可以让你的代码看起来很简洁
  • 去掉一堆没有意义的代码,只留下核心的逻辑

11. 线程同步

  • synchronized
  • public synchronized void method(int args){}
    • 同步块:synchronized (对象){}
  • 多个线程操作同一个资源
  • 队列+锁,保证线程安全性
  • 一个线程持有锁,会导致其他需要此锁的线程挂起
  • 损失性能
  • 优先级高的等待一个优先级低的线程释放锁,会导致优先级倒置

12. synchronized

  • 隐形的锁
  • 每个线程只有一个对象能加锁

13. 死锁:

  • 产生的必要条件
    • 互斥条件:一个资源每次只能被一个进程使用
    • 请求与保持条件:一个进程因请求资源而阻塞时,对方获得的资源保持不放
    • 不剥夺条件:进城已获得的资源,在未使用完之前,不能强行剥夺
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
  • 避免死锁
    • 破坏四个必要条件中的一个或多个就可以避免死锁的产生
package com.xiaojia;

public class Demo01 {
    public static void main(String[] args) {
        Makeup girlfriend1 = new Makeup(0,"第一任女朋友");
        Makeup girlfriend2 = new Makeup(1,"第二任女朋友");
        girlfriend1.start();
        girlfriend2.start();
    }
}
class Lipstick{

}
class Mirror{

}
class Makeup extends Thread{
    int choose;
    String girlfriend;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    /*
    static不能去掉,synchronized锁的静态对象
    */
    public Makeup(int choose,String girlfriend){
        this.choose = choose;
        this.girlfriend = girlfriend;
    }
    @Override
    public void run() {
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void makeup() throws InterruptedException {
        if (choose == 0){
            synchronized (lipstick) {
                System.out.println(this.girlfriend + "获得口红的锁");
                Thread.sleep(1000);
                synchronized (mirror) {
                    System.out.println(this.girlfriend + "想获得镜子的锁");
                }
            }
        }else {
            synchronized (mirror) {
                System.out.println(this.girlfriend + "获得镜子的锁");
                Thread.sleep(2000);
                synchronized (lipstick) {
                    System.out.println(this.girlfriend + "获得口红的锁");
                }
            }
        }
    }
}

14. lock

  • 显性的锁
  • ReentrantLock:可重入锁
  • 每个线程只有一个对象能加锁

15. synchronized与lock对比

  • lock实现时锁,需要手动打开和关闭
    synchronized是隐形锁,出了作用域自动释放
  • lock只有代码块锁
    synchronized有代码块锁和方法锁
  • lock锁,JVM将花费较少的时间去调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
  • 优先级顺序:
    • lock>同步代码块(已经入方法体,分配了相应资源)>同步方法(在方法体之外)

16. 线程协作

  1. 管程法
package com.xiaojia;
    
    public class Demo01 {
        public static void main(String[] args) {
            Containe containe = new Containe();
            Consumer consumer = new Consumer(containe);
            Productor productor = new Productor(containe);
            new Thread(consumer,"消费者").start();
            new Thread(productor,"生产者").start();
        }
    }
    
    //生产者
    class Productor implements Runnable{
    
        Containe containe = new Containe();
        //生产产品放在容器中
        public Productor(Containe containe){
            this.containe = containe;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                containe.push(new Chicken(i));
                System.out.println(Thread.currentThread().getName()+"生产了"+i+"只鸡");
            }
        }
    }
    
    //消费者
class Consumer implements Runnable{
    Containe containe = new Containe();
    //在容器中取出产品消费
    public Consumer(Containe containe){
        this.containe = containe;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            containe.pop(new Chicken(i));
            System.out.println(Thread.currentThread().getName()+"消费了"+i+"只鸡");
        }
    }
}

//产品
class Chicken{
    int id;
    public Chicken(int id) {
        this.id = id;
    }
}

//容器
class Containe{
    int count = 0;
    //容器能放10个产品
    Chicken[] chickens = new Chicken[10];
    //生产者放入产品
    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 void pop(Chicken chicken){
        if (count == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        chickens[count] = chicken;
        this.notifyAll();
    }
}
  1. 信号灯法
  package com.xiaojia.demo07;
    
    //线程协作:测试生产者消费者模型-->信号灯法:标志为解决
    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("小贾java课程播放中");
                }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++) {
                tv.watch();
            }
        }
    }
    //产品-->节目
    class TV{
        //演员表演,观众等待 T
        //观众观看,演员等待 F
        String voice;//表演的节目
        boolean flag = true;
        //表演
        public synchronized void play(String voice){
            if (!flag){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.voice = voice;
            System.out.println("演员表演了:"+voice);
            //通知观众观看
            this.notifyAll();//通知唤醒
            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;
        }
    }

17. 线程加入

package com.xiaojia;

public class Demo01 implements Runnable {
    public static void main(String[] args) {
        Demo01 demo01 = new Demo01();
        Thread thread = new Thread(demo01);
        thread.start();
        for (int i = 0; i < 1000; i++) {
            if (i == 600){
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main-->"+i);
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < 500; i++) {
            System.out.println("join-->"+i);
        }
    }
}
/*
* join线程是在某一时刻加入其他线程内部的,就好比插队现象
* 线程启动后,main线程和join线程一起跑,
* 当主线程跑到 i==600 时
* main线程停下,等待join线程跑完
* join线程跑完,main线程跟着跑完
* */

18. 线程停止

package com.xiaojia;

public class Demo01 implements Runnable{
    public static void main(String[] args) {
        Demo01 demo01 = new Demo01();
        new Thread(demo01).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main-->"+i);
            if (i==500){
                demo01.stop();
                System.out.println("线程该停止了");
            }
        }
    }

    public void stop(){
        flag = false;
    }

    private boolean flag = true;
    int i = 0;
    //定义 i 如果放入while循环内,则 i 的值一直被重置为0
    @Override
    public void run() {
        while (flag){
            System.out.println("线程运行-->"+i++);
        }
    }
}

19. 线程池

  • API查看ExecutorService和Executor
  • ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
    • void execute(Runnable command):执行任务/命令没有返回值,一般用来执行Runnable
    • Futuresubmit(Callable task):执行任务,有返回值一般用来执行Callable
    • void shutdown():关闭线程池
  • Executor:工具类、线程池的工厂类,用来创建并返回不同类型的线程池
package com.xiaojia.demo07;

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());
        service.execute(new MyThread());
        //2. 关闭链接
        service.shutdown();
    }
}

class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值