多线程与并发基础

普通方法调用

普通的方法调用是顺序执行的,只有主线程一条执行路径

多线程

多线程是多条执行路径,主线程与子线程并行交替执行。

三种创建方式

继承thread类

三个步骤

  1. 自定义线程类继承实现Thread
  2. 重写run方法,编写线程执行体
  3. 创建线程对象,调用Start()方法
/**
 * @Classname TestThread1
 * @Description 继承thread类 重写run方法,调用start开启线程
 * 注意:线程开启不一定立即执行,由cpu调度执行,所以可能先“学习多线程”再“看代码”
 * @Date 2020/12/24 16:10
 * @Created by ZZ
 */
public class TestThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("-------我在看代码"+i);
        }
    }

    public static void main(String[] args) {
        //创建一个线程对象 ,调用start方法开启线程
        TestThread1 testThread1 = new TestThread1();
        testThread1.start();
        for (int i = 0; i < 2000; i++) {
            System.out.println("我在学习多线程"+i);
        }
    }
}
  • @Description 继承thread类 重写run方法,调用start开启线程
  • 注意:线程开启不一定立即执行,由cpu调度执行,所以可能先“学习多线程”再“看代码”

实现Runnable 接口

三个步骤

  1. 自定义线程类实现Runnable接口
  2. 重写run方法
  3. 传入目标对象+Thread对象,调用start方法
TestThread2 t1 = new TestThread2("https://img-home.csdnimg.cn/images/20201224013137.jpg","1.jpg");
TestThread2 t2 = new TestThread2("https://img-home.csdnimg.cn/images/20201224042311.jpg","2.jpg");
TestThread2 t3 = new TestThread2("https://img-home.csdnimg.cn/images/20201224110946.png","3.jpg");
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();

实现Callable接口

  1. 可以定义返回值
  2. 可以抛出异常

如何选择?

一般情况下,不建议使用继承Thread,因为单继承具有局限性
推荐使用Runnable接口的方式,灵活方便,方便同一个对象被多个线程使用

初识并发问题

个人的理解:多个线程在操作同一个对象的时候,会有数据不安全的问题,这里的不安全大概指的是,比如说,当一个线程对一个数据进行更改的时候,这个时候另外一个线程进来了,就会导致数据的不一致性。

静态代理模式

我去帮你做事情
这里通过婚庆公司的案例来进行理解


/**
 * @Classname StaticProxy
 * @Description 什么是静态代理?
 * 通过婚庆公司得案例来理解
 * Runnable 接口和Thread代理都有run方法,最后调用得是Thread的start方法,
 *但实际执行的还是Runnable中的run方法中的方法体\
 * 静态代理模式总结:
 * 真实对象和代理对象都要实现同一个接口
 * 代理对象要代理真实角色
 *
 * 好处:
 * 真实对象专注做自己的事情
 * 代理对象可以做真实对象做不了的事情
 * @Date 2020/12/25 11:32
 * @Created by ZZ
 */
public class StaticProxy {
    public static void main(String[] args) {
        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
        //和线程的关系
        new Thread( ()-> System.out.println("我爱你") ).start();
        new  WeddingCompany(new You()).HappyMarry();
    }
}
interface  Marry{
    void HappyMarry();
}

//真实对象
class  You  implements Marry{
    public void HappyMarry() {
        System.out.println("我结婚了");
    }
}
//代理对象 婚庆公司
class  WeddingCompany implements  Marry{
 private  Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }

    private void before() {
        System.out.println("布置现场");
    }

    private void after() {
        System.out.println("收尾款");
    }
}

那么在线程当中的体现就是:

  • Runnable 接口和Thread代理都有run方法,最后调用得是Thread的start方法,
  • 但实际执行的还是Runnable中的run方法中的方法体

静态代理模式总结:

  • 真实对象和代理对象都要实现同一个接口
  • 代理对象要代理真实角色

多线程中的lambda表达式

lambda表达式的演变过程

  • 最开始,写一个函数式的接口,然后定义一个实现的类,在主方法中调用该类
  • 静态内部类
  • 局部内部类
  • 匿名内部类(没有类的名称,必须借助接口或者父类)
  • Lambda表达式简化

函数式接口和lambda表达式密切相关
理解Functionnal Interface (函数式接口) 是学习java8 Lambda表达式的关键所在

  • 函数式接口的定义:
    任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口(有了函数式接口才能使用lambda表达式)
  • 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

lambda总结:

  • lambda表达式只有一行代码的情况下才能简化成一行,否则使用代码块
  • lambda的前提是使用函数式接口
  • 多个参数可以去掉参数类型,要去掉都去掉,必须加括号

线程的状态

线程的几种状态转换
线程状态的解释:

1、线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,但不管怎样, 当我们new了这个对象后,线程就进入了初始状态;
2、当该对象调用了start()方法,就进入就绪状态;
3、进入就绪后,当该对象被操作系统选中,获得CPU时间片就会进入运行状态;
4、进入运行状态后情况就比较复杂了
4.1、run()方法或main()方法结束后,线程就进入终止状态;
4.2、当线程调用了自身的sleep()方法或其他线程的join()方法,进程让出CPU,然后就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资源即调用sleep ()函数后,线程不会释放它的“锁标志”。)。当sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配CPU时间片。典型地,sleep()被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。
4.3、线程调用了yield()方法,意思是放弃当前获得的CPU时间片,回到就绪状态,这时与其他进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态; 调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间片从而需要转到另一个线程。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
4.4、当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被synchroniza(同步),获取不到锁标记,将会立即进入锁池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入就绪状态,等待OS分配CPU时间片;

4.5. suspend() 和 resume()方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume()被调用,才能使得线程重新进入可执行状态。典型地,suspend()和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume()使其恢复。
4.6、wait()和 notify() 方法:当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。

线程的状态转换

停止线程

不推荐使用jdk提供的stop和destroy方法
推荐自己使用一个标志位进行终止变量,当flag=false,则终止线程运行

sleep和wait的区别

Thread类的方法:sleep(),yield()等
Object的方法:wait()notify()

由于sleep()方法是Thread类的方法,因此它不能改变对象的锁。所以当在一个Synchronized方法中调用sleep()时,线程虽然休眠了,但是对象的机锁没有被释放,其他线程仍然无法访问这个对象。而wait()方法则会在线程休眠的同时释放掉机锁,其他线程可以访问该对象。

sleep()

1、属于Thread类,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态

2、sleep方法没有释放锁

3、sleep必须捕获异常

4、sleep可以在 任何地方使用

wait()

1、属于Object,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程

2、wait方法释放了锁

3、wait不需要捕获异常

4、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用

yield()

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

守护线程

线程分为用户线程和守护线程,虚拟机必须确保用户线程执行完毕而无序等待守护线程执行完毕。
比如后台记录惭怍日志的时候没有监控内存,垃圾回收等待

线程同步(重点和难点)

多个线程操作一个对象,会存在安全问题。解决的办法:
线程同步:

  • 一种等待机制,等待的线程在等待池形成等待队列
  • 线程访问对象的时候需要一把锁,才能获得访问的权限

synchronized
同步方法和方法块

  • 同步方法存在弊端,一般对于需要修改的代码才需要锁,直接对整个方法锁的话会浪费资源,效率低下
  • 同步方法块:
    synchronized(Obj){}
    obj 称为同步监视器,它是一个对象,锁的是对象,执行的是代码块

死锁

注意:死锁是指进程的执行过程
多个进程都各自占有一定的资源,并且相互等待其他进程的资源才能运行,在这种情况下就会发生死锁。发生死锁的主要条件是,在某一个同步块同时拥有2个以上的锁

死锁的必要条件:

  • 互斥条件,每个资源只能被一个进程使用
  • 请求与保持条件,一个线程因为请求资源而阻塞的时候,对已获得的资源保持不放
  • 不剥离条件 不能强行剥夺进程已经获得的资源
  • 循环等待条件

Lock锁

synchronized是隐式锁,而lock是显示锁
在这里插入图片描述

线程的通信

基础的理解:
主要是wait方法和notify方法

线程池

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());

    }
}
已标记关键词 清除标记
相关推荐
<p> <b><span style="background-color:#FFE500;">【超实用课程内容】</span></b> </p> <p> <br /> </p> <p> <br /> </p> <p> 本课程内容包含讲解<span>解读Nginx的基础知识,</span><span>解读Nginx的核心知识、带领学员进行</span>高并发环境下的Nginx性能优化实战,让学生能够快速将所学融合到企业应用中。 </p> <p> <br /> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><br /> </b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><span style="background-color:#FFE500;">【课程如何观看?】</span></b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> PC端:<a href="https://edu.csdn.net/course/detail/26277"><span id="__kindeditor_bookmark_start_21__"></span></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 移动端:CSDN 学院APP(注意不是CSDN APP哦) </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 本课程为录播课,课程永久有效观看时长,大家可以抓紧时间学习后一起讨论哦~ </p> <p style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <br /> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <strong><span style="background-color:#FFE500;">【学员专享增值服务】</span></strong> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b>源码开放</b> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化 </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 下载方式:电脑登录<a href="https://edu.csdn.net/course/detail/26277"></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a>,播放页面右侧点击课件进行资料打包下载 </p> <p> <br /> </p> <p> <br /> </p> <p> <br /> </p>
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页