多线程基础

时间:2021-03-08 09:35:57   收藏:0   阅读:27

多线程简介:

多条线路同时跑起来去执行任务

普通方法与多线程方法的区别

普通方法调用:

 

 

 

技术分享图片技术分享图片

多线程方法调用:

技术分享图片

进程(Process)与线程(Thread)

小知识

很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器,如果是模拟出来的多线程,在一个CPU的情况下,在同一个时间点CPU只能执行一个代码,但因为切换的很快,所以会有同时执行的错觉

线程的三种创建方式

Thread class —— 继承Thread类(重点)

自定义线程类继承Thread类

重写run()方法,编写线程执行体

创建线程对象,调用start()方法启动线程

创建Thread2类进行多线程下载图片操作。

 

导入commons-io包

 

构建下载图片方法

 

编写下载图片的执行体

 

执行结果

 

Runnable接口 —— 实现Runnable接口(重点)

以此代码为例,与继承Thread方法相比,运行的方式变成new一个Thread对象,将继承了Runnable的类放进去进行使用start运行

小结:

为什么选择实现Runnable接口来创建多线程

继承Thread类

实现Runnable接口

结合案例(龟兔赛跑)

 

Callable接口 —— 实现Callable接口(了解即可)

 

静态代理模式

public class StaticProxy {
  public static void main(String[] args) {
?
      new Thread(()-> System.out.println("我爱你")).start();
?
      new WeddingCompany(new You()).happyMarry();
?
//       WeddingCompany weddingCompany = new WeddingCompany(new You());
//       weddingCompany.happyMarry();
  }
}
?
interface Marry{
  void happyMarry();
}
?
//真实角色(本人),去结婚
class You implements Marry{
?
  /**
    * 本人重写的结婚方法(只需要结婚)
    */
  @Override
  public void happyMarry() {
      System.out.println("温莹要结婚了");
  }
}
?
//代理角色(婚庆公司),帮助结婚
class WeddingCompany implements Marry{
?
  /**
    * 代理角色代理真实角色
    */
  private Marry target;
?
//   因为结婚是本人和婚庆公司都需要使用的方法,本人只需要负责结婚,婚庆公司负责布置现场和收取尾款,此处需要传真实角色(本人)的对象
  public WeddingCompany(Marry target) {
      this.target = target;
  }
?
  /**
    * 婚庆公司重写的结婚方法(结婚之前布置现场,结婚后收取尾款)
    */
  @Override
  public void happyMarry() {
      before();
      this.target.happyMarry();
      after();
  }
?
  private void after() {
      System.out.println("结婚之后,收尾款");
  }
?
  private void before() {
      System.out.println("结婚之前,布置现场");
  }
}
?

静态代理模式总结:

好处:

Lamda表达式

概念:属于函数式编程

为什么要使用它?

理解Functional Interface(函数式接口)是学习java8 lambda表达式的关键所在

函数式接口定义:

使用lambda表达式简化代码:

lambda表达式的简化:

局限:

 

线程状态

线程核心方法

停止线程

线程休眠

线程礼让

线程强制执行

观测线程状态

线程优先级

线程优先级低只是意味着获得调度的概率低,优先级高的也只是概率高,具体调动还是看CPU

守护线程

线程同步

多个线程操作同一个资源被称为并发

如何处理并发

不安全案例:

不安全的取钱

不安全的买票

不安全的集合

同步块:

解决方法:

使用同步块锁account取钱:

加锁买票:

使用同步块锁list集合

死锁

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有两个以上对象的锁时,就可能发生死锁问题

案例:化妆

这个最终结果是王婷婷获得口红的锁,温莹获得镜子的锁,程序在此处僵持。解决:

产生死锁的四个必要条件:

lock(锁)

不加lock锁时线程可能会同时取到相同的值,或者取到负值。加了lock锁后线程按顺序抢票

定义Lock锁:

class A{
private final ReentranLock lock = new RenntranLock();
public void m(){
//开启锁
lock.lock();
try{
//保证线程安全的代码
}finally{
//关闭锁
lock.unlock();
}
}
}

 

sychronized与lock的对比

线程协作

应用场景:生产者消费者模式

分析:

java提供了几个方法解决线程之间的通信问题

解决方法一(管程法):

并发协作模型生产者/消费者模式--->管程法

解决方法二(信号灯法):

并发协作模型生产者/消费者模式--->信号灯法

//测试生产者消费者问题2:信号灯法,标志位解决
public class TestPc2 {
  public static void main(String[] args) {
      TV tv = new TV();
      new Player(tv).start();
      new Watcher(tv).start();
  }
}
?
//生产者---演员
class Player extends Thread{
  TV tv;
  public Player(TV tv){
      this.tv = tv;
  }
?
  @Override
  public void run() {
      for (int i = 0; i < 20; i++) {
          if(i%2==0){
              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++) {
          tv.watch();
      }
  }
}
?
//产品---节目
class TV{
?
//   表演的节目
  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;
  }
?
}

线程池

//测试线程池
public class TestPool {
?
  //   此处加同步锁锁不住
  public static void main(String[] args) {
      //1.创建服务,创建线程池
//       newFixedThreadPool 参数为:线程池大小
      ExecutorService service = Executors.newFixedThreadPool(10);
      MyThread myThread = new MyThread();
//       此处加同步块锁service锁不住,锁myThread也锁不住
//       正常运行是多线程运行,Thread1和Thread2交替输出
      service.execute(myThread);
      service.execute(myThread);
//       2、关闭连接
      service.shutdown();
  }
}
?
?
class MyThread implements Runnable{
  //   定义Lock锁
  private final ReentrantLock lock = new ReentrantLock();
?
//   此处加同步锁可以锁住
  @Override
  public void run() {
//       此处加lock锁,可以保证只有一条线程占用资源,输出完成后,下一条线程再占用输出
//       lock.lock();
      for (int i = 0; i < 100; i++) {
          System.out.println(Thread.currentThread().getName()+"王"+i);
      }
//       lock.unlock();
  }
}

 

原文:https://www.cnblogs.com/yunchuran/p/14497810.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!