多线程

进程三种状态

  1. 就绪状态:当进程分配到除了CPU以外的所有资源,只要在获得CPU,就可以立即执行的时候,进程这时的状态就被称为就绪状态。系统中处于就绪的进程可能有多个,通常他们排成一个队列,称为就绪队列
  2. 执行状态:进程已经获得CPU,正在执行。在单处理机系统,只有一个进程处于执行状态;在多处理机系统,有多个进程处于执行状态
  3. 阻塞状态:正在执行的进程,由于等待某个实践发生而无法执行,便放弃处理机而处于阻塞状态。引发阻塞的实践可能有多种。等待IO完成,申请缓冲区不能满足,等待信号。

状态转换图
在这里插入图片描述

  • 就绪-》执行:分配了处理机之后
  • 执行-》就绪:在执行过程中,因为分配给他的时间片用完了而不得不让出处理机
  • 执行-》阻塞:由于某些IO请求发生导致无法继续执行
  • 阻塞-》就绪:等待的请求已经发生,就从阻塞转为就绪

进程和线程

  • 进程:是并发执行程序的资源分配的基本单位
  • 线程:是进程的一个执行单元,比进程更小的独立运行大的基本单位,线程是处理器调度的基本单位
  • 地址空间:同一进程的线程共享本进程的地址空间,而进程之间是独立的地址空间
  • 资源拥有:同一进程的线程共享本进程的资源(内存,IO,cpu),但是进程之间资源是独立的
  • 优缺点:
    • 线程开销小,但是不利于资源的管理和保护
    • 进程开销大,但是能很好的进行资源的管理和保护
  • 对资源管理和保护要求高,不限制开销和效率,使用多进程;要求效率高,频繁切换时,资源保护管理要求不高,使用多线程

多线程

  • 并行:多个处理器同时处理多个不同的任务

  • 并发:一个处理器可以同时处理多个任务,按细分的时间片轮流交替执行

  • 进程和线程

    • 进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程
    • 进程拥有独立的内存单元,多个线程共享这些内存单元
    • 多线程减少切换次数,提高效率,同一个进程的多个线程可以并发执行(一个处理器处理)
  • 守护线程:运行在后台的特殊进程,独立于控制终端并且周期性的执行某种任务,java垃圾回收线程就是特殊的守护线程

  • m个进程共享同一资源,若使用信号量机制实现临界资源的互斥访问,则信号量的变化范围是:1到-(m-1)

    • 1表示没有进程占用资源
    • 信号量小于零代表有进程占用了,-(m-1)代表m个进程中有m-1个在等待

创建线程三种方法

- 继承Thread重写run方法
- 实现Runnable接口
- 实现Callable接口
  • 采用实现Runnable,Callable接口方式
    • 优势:线程类只实现了runnable,callable接口,但还可以继承其他类
    • 多线程可以共享一个target对象,适合多个相同线程处理同一份资源的情况
    • 劣势:编程复杂,要访问当前线程必须使用Thread.currentThread()方法
  • 使用继承Thread类的方式
    • 编写简单,访问当前线程直接使用this即可获取
    • 劣势:线程类已经继承了Thread类,就不能再继承其他类
  • Runnable和Callable区别
    • Callable重写的是call(),Runnable重写的是run()方法
    • Callable执行后可返回值,Runnable没有返回值
    • call可以抛出异常,run不可以
    • runnable对象作为target创建Thread对象,FutureTask对象作为target创建Thread对象
1.继承Thread类创建线程类,并重写该类的run方法(线程执行体)
创建thread子类的实例,即线程对象(new)
调用线程对象的start方法启动线程
public calss FirstThread extends Thread{
    public void run{  
        //run方法就是线程要执行的任务
    }
    
    public static void main(String[] args)
    {
        new FirstThread.start();//创建线程对象,并用start启动线程
    }
}

2.实现runnable接口实现类,并重写接口的run方法(线程执行体)
创建runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象
public class RunnableThread implements Runnable
{
    public void run()
    {
        
    }
    public static void main(String[] args)
    {
        RunnableThread runner = new RunnableThread();
        new Thread(runner,"新线程1").start();
    }
}

3.实现Callable接口的实现类,并实现call()方法(该方法是线程执行体,并有返回值)
使用FutureTask对象作为Thread对象的target创建并启动线程

public calss CallableThread implements Callable<Integer>
{
    public static void main(String[] args)
    {
        CallableThread ctt = new CallableThread();
        FutureTask<Integer> ft = new FutureTask();
        for(int i =0;i<100;i++)
        {
            new Thread(ft,"有返回值的线程").start();
        }
        try
        {
            log.info("返回值"+ft.get());
        }catch()
    }
}


线程状态

  • 五种:创建,就绪,运行,阻塞,死亡
  • 创建:生成线程对象,并没有调用对象的start方法
  • 就绪:调用了start方法之后进入就绪,但线程调度程序并没有把该线程设置成当前线程。线程运行之后,从等待或睡眠中回来之后,也会处于就绪
  • 运行:线程调度程序把处于就绪状态的线程设置成当前线程,进入运行状态,开始运行run函数
  • 阻塞:线程正在运行,被暂停,通常是为了等待某个时间(某项目资源就绪)之后再继续运行,sleep,suspend,wait都可导致线程阻塞
  • 死亡:线程的run方法执行结束或者调用stop方法后,线程就会死亡。无法在使用start让其进入就绪

suspend()和resume()

  • 两个方法配套使用,suspend使线程进入阻塞状态,并且不会自动恢复。必须调用resume后线程才回到可执行状态

run和start

  • 调用run后,程序中依然只有主线程这一个线程,程序执行路径还是只有一条,还是顺序执行。
  • start开启多线程,真正实现了多线程
public static void main(String args[]) {
        Thread t = new Thread() {
            public void run() {
                pong();
            }
        };
        t.run();
     System.out.print("ping");
    }
    static void pong() {
        System.out.print("pong");
      }
//run()方法不会启动新的线程,这里只有一个主线程,所以顺序执行,假如这里用start()方法,就会启动新的线程,而ping和pong两个线程并不知道哪个先执行就是答案就是顺序不确定

sleep和wait区别

  • 第一种解释:功能差不多,都是进行线程控制,但是sleep不释放同步锁,wait释放同步锁,sleep必须捕获异常,wait不用捕获异常
  • sleep(milliseconds)可以用时间指定
    来使他自动唤醒,没到达时间可以使用interreput()来强行打断,wait可以直接用notify唤醒
  • 第二种解释:sleep是Thread类的静态方法,sleep的作用是让线程休眠一定的时间,在时间到达时恢复
  • wait是Object方法,也就是说可以对任意对象调用wait方法,调用wait会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活
try{
    System.out.println("go to bed");
    Thread.sleep(1000);
    System.out.println("wake up");
}
catch(IntrruptedException e){
    
}
try{
    obj.wait(); //直到调用obj.notify()才会激活
}

notify和notifyAll

  • 如果线程调用了wait方法,那么线程将进入该对象的等待池中,等待池的线程不会去竞争该对象的锁
  • notify(随即唤醒一个wait线程),notifyAll(唤醒所有wait线程),被唤醒的线程会进入该对象的锁池中,锁池中的线程会去竞争该对象锁
  • 优先级高的线程竞争到对象锁的概率大,没有竞争到锁就继续留在锁池里,竞争到对象锁的线程继续执行,执行完synchronized代码块,他会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

创建线程池五种方式

  • 线程池:提高效率,创建好一定数量的线程,等需要使用时就从池里拿出一个,比需要的时候在创建要快。方便股那里可以编写线程池股那里代码统一管理。
  • newFixedThreadPool(int nThreads),创建一个固定长度的线程池,可控制线程最大并发数,超出的线程会在队列中等待
  • newCacheThreadPool,创建一个可缓存的线程池,如果线程池规模超过处理需求,将自动回收空闲线程
  • newSingleThreadExecutor,创建单个工作线程来执行任务,他只会用唯一的工作线程来执行任务,保证任务按照指定顺序执行
  • newScheduledThreadPool,创建固定长度的线程池,支持定时及周期性任务执行
  • java线程安全三个体现:
    • 原子性:提供互斥访问,同一时刻只有一个线程对数据操作
    • 可见性:一个线程对主内存的修改可以及时被其他线程看见
    • 有序性:

线程池的状态

  • running,shutdown,stop,tidying,terminated

synchronized(同步)和ReentrantLock(锁)

  • 两者都是java同步机制,提供了互斥语义和可见性,当线程获得资源之后,其他竞争资源的线程必须等待或者阻塞

synchronized作用

  • 静态synchronized方法调用情况:如果一个对象的synchronized方法被某个线程执行,那么其他线程无法访问该对象的任何synchronized方法(但可以调用其他非synchronized方法)。直至该synchronized方法执行完成

  • 区别一:使用

  • synchronized既可以修饰方法,也可以修饰代码块。reentrantlock修饰java类

public synchronized void test(){
    
}
synchronized(Object){
    //括号中表示需要锁的对象
    //线程执行的时候会对Object上锁
}
  • ReentrantLock的使用
public calss test(){
    private LOck lock = new ReentrantLock();
    public void testMethod(){
        try{
            lock.lock();
        }
        finally{
            lock.unlock();
        }
    }
}
  • 区别二:是否等待可中断

  • 等待可中断是指当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。

  • 两个线程Thread1和Thread2,假如Thread1获取了对象的object锁,Thread2将等待对象的object锁

    • synchronized(同步),如果Thread1不释放,Thread2将一直等待,不能被中断。synchronized是java提供的原子性内置锁机制,内部锁扮演了互斥锁的绝色
    • ReentrantLock,如果Thread1不释放,Thread2等待了很长时间,可以中断等待,转而去做别的事情。
  • 区别三:公平锁

  • 公平锁是多个线程等待同一个锁的时候,必须按照申请的时间顺序获得锁。

  • 非公平锁在被释放的时候,任何一个等待锁的线程都有机会获得锁

    • synchronized的锁是非公平锁
    • ReentrantLock默认也是非公平锁,但可以通过带布尔值的构造函数要求使用公平锁
  • 区别四:锁绑定多个条件

    • synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件,但如果要和多于一个的条件关联,就不得不额外添加一个锁
    • ReentrantLock可以同时绑定多个Condition对象,只需要多次调用newCondition方法即可

reentrantlock功能多一点

  • 底层实现:
    • synchronized
    • lock锁底层基于votatile和CAS
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值