zoukankan      html  css  js  c++  java
  • 多线程与高并发学习笔记(持续更新中)

    一、 基础概念

    什么是线程

    • 什么是进程?什么是线程?
      进程是系统中正在运行的一个程序,程序一旦运行就是进程。

    进程可以看成程序执行的一个实例。进程是系统资源分配的独立实体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构,如果想让一个进程访问另一个进程的资源,需要使用进程间通信,比如管道,文件,套接字等。

    一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。线程与进程的一个主要区别是,统一进程内的一个主要区别是,同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。同时,每个线程还拥有自己的寄存器和栈,其他线程可以读写这些栈内存。

    线程是进程的一个实体,是进程的一条执行路径。

    线程是进程的一个特定执行路径。当一个线程修改了进程的资源,它的兄弟线程可以立即看到这种变化。

    • 进程和线程的区别体现在以下几个方面:
      1.地址空间和其他资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其他进程内不可见。

    2.通信:进程间通信IPC(管道,信号量,共享内存,消息队列),线程间可以直接独写进程数据段(如全局变量)来进程通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。

    3.调度和切换:线程上下文切换比进程上下文切换快得多。

    4.在多线程OS中,进程不是一个可执行的实体。

    • 进程和线程的选择取决以下几点:
      1.需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程的代价是很大的。

    2.线程的切换速度快,所以在需要大量计算,切换频繁时使用线程,还有耗时的操作时用使用线程可提高应用程序的响应。

    3.因为对CPU系统的效率使用上线程更占优势,所以可能要发展到多机分布的用进程,多核分布用线程。

    4.并行操作时用线程,如C/S架构的服务器端并发线程响应用户的请求。

    5.需要更稳定安全时,适合选择进程;需要速度时,选择线程更好。

    线程的实现

    继承Thread类或者实现Runnable接口

    package com.mashibing.juc.c_000;
    
    public class T02_HowToCreateThread {
        static class MyThread extends Thread {
            @Override
            public void run() {
                System.out.println("Hello MyThread!");
            }
        }
    
        static class MyRun implements Runnable {
            @Override
            public void run() {
                System.out.println("Hello MyRun!");
            }
        }
    
        public static void main(String[] args) {
            new MyThread().start();
            new Thread(new MyRun()).start();
            new Thread(()->{
                System.out.println("Hello Lambda!");
            }).start();
        }
    
    }
    
    //请你告诉我启动线程的三种方式 1:Thread 2: Runnable 3:Executors.newCachedThrad
    
    • yield
      Thread.yield()方法作用是:暂停当前正在执行的线程对象(及放弃当前拥有的cup资源),并执行其他线程。

    yield()做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的
    目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被
    线程调度程序再次选中。

    结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果

    • join
      大白话:就是谁调用这个方法,就让调用此方法的线程进入阻塞状态,等待我执行完毕之后,再往下执行;

    那么我们再来看上面那段加了join()的代码,首先开启线程A,紧接着线程A调用了join()方法进入阻塞状态,那么线程必须等待线程A执行结束之后再往下执行,线程A执行完毕,线程B开启,进入睡眠,主线程执行,线程B睡眠结束,执行;
    知乎-关于join的解释

    线程状态

    线程生命周期

    • 新建状态:
      使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
    • 就绪状态:
      当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
    • 运行状态:
      如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
    • 阻塞状态:
      如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入- - 就绪状态。可以分为三种:
      • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
      • 同步阻塞:线程在获取 synchronized同步锁失败(因为同步锁被其他线程占用)。
      • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
    • 死亡状态:
      一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

    线程同步

    • synchronized 代码块
    • synchronized方法
    • 从JDK1.5开始的Lock接口替代synchronized关键字

    sychronized 锁升级

    https://blog.csdn.net/tongdanping/article/details/79647337

    sychronized 同步方法与非同步方法

    sychronized 锁重入

    异常与锁

    volatile

    AtomicXXX

    wait notify

  • 相关阅读:
    ymnets----框架内功能了解
    ymnets----代码生成
    关于分层架构
    SQL——抛出错误
    Jump Game
    combination sum && combination sum II
    35-Search Insert Position
    33-Search in Rotated Sorted Array
    34- Find First and Last Position of Element in Sorted Array
    机器学习实战之SVM
  • 原文地址:https://www.cnblogs.com/yuuken/p/13498182.html
Copyright © 2011-2022 走看看