多线程基础

几个概念

进程:程序的一次运行(从程序开启->程序结束)

线程:操作系统调度的基本单位
    线程不可独立,必须依附在进程之下

并行:两个或多个事件在同一时刻发生
并发:两个或多个事件在同一段时间内发生

进程是程序运行的实例
进程是OS分配系统资源的单元

多线程程序:多个线程并发执行的程序

线程的创建方式

线程的四种创建方式:
    继承Thread类
    实现Runnable接口
    实现Callable接口
    线程池创建

继承Thread类,重写run方法
    class MyThread extends Thread{
        @override
        public void run(){
            // ....
        }
    }
    
    Thread t=new MyThread("myThread");
    t.start();

创建一个打印线程

继承Thread类开启线程的缺点:Java只运行单继承,但一个继承Thread之后便无法再有其他父类的,这是不好的。

实现Runnable接口
    class MyRunnable implements Runnable{
        public void run(){
            //...
        }
    }

    Thread t=new Thread(new MyRunnable(),"myRunnable");
    t.start();

实现Callable接口
    Future接口方法:isDone;cancel;get

    class MyCallable implements Callable<String>{
        public String call(){
            // ...
        }
    }
    //call方法是有返回结果的

线程池创建 Executor
    ExecutorService e = Executers.newFixedThreadPo ol(10);
    
    e.execute(new Runnable());
    
实现接口和继承Thread开启线程的比较
    接口更适合多个相同的程序代码的线程去共享一个资源
    接口可以避免java中的单机成的局限性
    接口代码可以被多个线程共享,代码和线程独立
    线程池只能放入Runnable或Callable接口的线程

Runnable和Callable接口比较
    Callable接口的线程能返回执行结果
    Callable接口的call方法运行抛出异常
    实现Callable接口的线程可以调用Future.cancle取消执行
    (Callable接口支持返回执行接口,此时调用FutureTast.get获取到线程执行的结果,FutureTast.get会阻塞主调这,直至得到线程的执行结果)

多线程控制类

为了保证多线程的三个特性,Java引入了很多线程控制机制,如:
    ThreadLocal:线程本地变量
    yuanzi lei:保证变量的氧原子操作
    Lock类:保证线程有序性
    Volatile:保证线程变量可见性

ThreadLocal
    ???不是很明白
    ThreadLocal提供线程局部变量,即为使用线条变量的每一个线程维护一个该变量的副本。当某些数据时一个数据为作用域并且并且不同线程为不

多线程特性

原子性
    院子性,一个操作或多个操作要么全部执行,并且执行过程背会被任何因素打断,要么不执行

可见性
    可见性是指多个线程访问一个变量,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值
    (对于单线程而言,可见性问题是不存在的)

有序性
    有序性即一些代码的执行顺序应当是被有先后的

线程安全问题

线程安全概念
    ???

多个线程对共享数据有写操作时,就有可能会发生线程安全问题

线程同步
    七种线程同步机制
        同步代码块
        同步方法
        同步锁(reenreantlock)
        特殊域变量(volatile)
        局部变量(ThreadLocal)
        阻塞队列(linkedBlokingQueue)
        原子变量(atomic)

同步方法的同步锁
    对于非static方法,同步锁为this
    对于static方法,同步锁为.class字节码对象

同步锁
    lock.lock();
    try{
        //...
    }
    finally{
        lock.unlock();
    }
    一旦lock开启之后,必须unlock否则会死锁

sychronized和Lock区别
    sychronized是关键字,在jvm层面,Lock是个Java类
    synchronized无法判断是否获取锁的状态
    synchronized会自动释放锁,Lock需要手动释放锁
    sychronized受关联的两线程,如果一个线程持有锁,另一个线程会一直等待锁的释放;Lock则如果尝试获取不到锁,线程可以不用一直等待就就是了
    synchronized锁可冲入,不可中断,非公平,Lock锁可冲入,可中断,可公平
    lock锁适合大量同步代码的同步问题,synchronized锁适合代码少量的同步问题
    
    

线程生命周期

新建NEW
    new关键字创建一个线程之后,该线程就处于新建状态
    JVM为线程分配内存,初始化成员变量值

就绪
    当线程对象调用start方法后,该线程处于就像状态
    JVM为线程创建方法栈和程序计数器,等待线程调度器调用

运行
    就绪状态的线程获得CPU资源,开始运行run方法

阻塞
    当发生如下情况,线程会进入use状态
        线程调用sleep方法主动放弃所占用的处理器资源
        线程调用一个阻塞式IO方法,在该方法返回时,该线程处于阻塞状态
        线程试图获得一个同步锁(同步监视器),但该同步监视器正在被其他线程所持有
        线程在等待某个通知(notify)
        程序调用线程的suspend方法将线程挂起(这个方法容易导致死锁,应当比避免使用)

死亡
    线程会以如下三种方式结束,结束后处于死亡状态
        run或call方法执行完成,线程正常结束
        线程抛出一个未捕获的Exception和Error
        线程调用stop结束线程(该方法容易导致死锁,应避免使用)
    

线程死锁

死锁:多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些线程都将无法向前推进

死锁的产生
    互斥条件
    不可剥夺条件
    请求与保持条件
    循环等待条件

产生死锁的代码

死锁处理
    预防死锁
    避免死锁
    检测死锁
    解除死锁

线程通信

线程间常用的通信方式如下:
    休眠唤醒方式
        Object的wait、notifuy、notifyAll
    CountDownLatch用于某个线程等待其他线程执行完后执行
    CyclicBarrier一组线程等待至某个状态之后再全部同时执行
    Semaphore:用于控制对某组资源的访问权限

休眠唤醒方式
    多线程打印奇偶数
    notyfy() wait() 必须放在sychronized代码块中

CountDownLatch
    等待多个线程执行完毕后在执行
    
    9:14

标签

评论


© 2021 成都云创动力科技有限公司 蜀ICP备20006351号-1