安卓软件开发需要学什么软件,北京百度推广优化公司,可口可乐网络营销推广方案,saas建站平台源码线程简介 这里先说明一下#xff0c;进程和线程是不同的 进程#xff1a;程序的执行过程#xff0c;是一个独立的运行环境#xff0c;持有资源和线程#xff0c;相当于一个应用程序#xff0c;操作系统在分配资源时把资源分配给进程(堆和方法区是属于进程的) 线程#x… 线程简介 这里先说明一下进程和线程是不同的 进程程序的执行过程是一个独立的运行环境持有资源和线程相当于一个应用程序操作系统在分配资源时把资源分配给进程(堆和方法区是属于进程的) 线程进程中执行的一个任务系统中最小的执行单元同一进程有多个线程线程共享进程的资源CPU资源分配给线程(程序计数器和栈是属于线程的) 创建一个线程Thread时JVM将分配一大块内存到专为线程保留的特殊区域上用于提供运行任务时所需的一切包括 程序计数器指明要执行的下一个JVM字节码指令由于线程是占有CPU执行的基本单位CPU是用时间片轮转的方式当前线程时间片用完之后需要让出CPU而程序计数器就是记录该线程让出CPU时的执行地址等到下次分配到时间片时线程就可以从本身私有的计数器中指定的地址继续执行 用于支持Java代码执行的栈包含有关线程已到达当时执行位置所调用方法的信息(调用栈帧)以及每个正在执行的方法的所有局部变量 第二个则用于native code执行的栈 线程本地变量的存储区域 用于控制线程的状态管理变量 每当调用一个方法时当前程序计数器被推到该线程的栈上然后栈指针向下移动以足够来创建一个栈帧其栈帧里存储该方法的所有局部变量参数和返回值。所有基本类型变量都直接在栈上虽然方法中创建对象的任何引用都位于栈帧中但对象本身存于堆中。 创建线程的方式 继承Thread类并且重写run方法 实现Runnable接口使用带参的Thread构造器来创建Thread对象 实现Callable接口使用FutureTask的方式使用带参的Thread构造器来创建Thread对象该方式可以获取到线程执行的返回结果 FutureTaskInteger futureTask new FutureTask(call);new Thread(futureTask).start(); 使用线程池 调用start()方法才会调用线程如果直接调用run()方法和普通的方法没有区别 创建一个Thread类的实例与创建其他类不同JVM会为一个Thread实例分配两个调用栈所需的内存空间一个调用栈用于跟踪Java代码间的调用关系另一个用于跟踪Java代码对本地代码(native代码)的调用关系。且一个Thread实例通常对应两个线程一个是JVM中的线程另一个是与JVM中的线程相对应的依赖于JVM宿主机操作系统的本地(Native)线程 实现Runnable接口比继承Thread的优势 代码可被多个线程共享适合多个相同的代码去处理同一个资源 可以避免java单继承的限制 增加程序的健壮性代码和任务分离 方法介绍 join() 线程加入进来要等待该线程执行完在继续执行join之后的代码可以确保两个线程的执行顺序 t1.start(); t1.join(); // 等待t1线程执行完成再执行t2.start()t2.start(); join是当前线程等待所join的线程先执行完才继续进行如果是多个线程的话需要在线程的run方法中调用前一个线程的join yield() 暂停当前正在执行的线程并执行其他线程yield()方法会使当前线程让出CPU使用权从运行状态变成就绪状态重新争抢cpu sleep() 在指定的时间内让当前正在执行的线程休眠暂时让出指定时间的执行权在这期间不参与CPU的调度但是该线程所拥有的监视器资源不会让出。使用sleep(0)可以暂时释放cpu从运行状态变成就绪状态这样可以让其他线程获得cpu 在hotspot中sleep(0)的作用相当于yield() getState() 获取线程状态 wait() Object的wait()方法、notify()、notifyAll()方法必须要与synchronized(obj)一起使用只能针对已经获取到obj锁的情况否则会抛出”java.lang.IllegalMonitorStateException“异常。wait()方法会释放该对象的锁资源从而进行阻塞notify()方法会通知等待该对象资源的线程进行唤醒 interrupt()方法中断线程将中断状态设置为true但是不一定会被中断只有在阻塞时才会被中断而抛出InterruptedException异常 public void interrupt() { if (this ! Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b blocker; // 只有被阻塞才会抛出异常 if (b ! null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } // 该方法只会设置中断标志为true实际上并没有被中断还是会继续执行 interrupt0();} isInterrupted()方法实例方法检查当前线程是否被中断如果是返回true调用该方法不会改变中断状态 interrupted()方法静态方法检查线程是否被中断与isInterrupted()不同的是该方法如果发现当前线程被中断则会清除中断标志将中断状态重置为false且该方法是静态方法判断的是当前调用线程的中断标志而不是调用该方法的实例对象的中断标志 sleep和wait的区别 sleep()是Thread的静态方法wait()是Object的方法 sleep()和wait()虽然都释放CPU但是如果线程持有对象锁资源的话sleep()在休眠时不释放锁资源wait()在等待时会释放锁资源 sleep()需要捕获异常wait()不需要 sleep()可以在任意位置使用wait()必须要在synchronized同步块内使用 wait()当前线程必须拥有对象的监视器 线程阻塞 当执行Thread.sleep方法时会一直阻塞指定时间或者阻塞被另一个线程打断 当线程执行wait方法时会一直阻塞到接到通知(notify方法)或者被中断或者经过指定时间为止 上下文切换 一般情况下使用多线程的时候使用的线程个数会大于CPU个数但是每个CPU同一时刻只能被一个线程使用CPU资源采用了时间片轮转的策略为每个线程分配一个时间片当前线程的时间片到后会处于就绪状态让出CPU这就是上下文切换而在上下文切换时需要保存当前线程的执行现场当再次执行时根据保存的执行现场信息恢复执行现场 线程上下文切换的时机 当前线程的CPU时间片用完处于就绪状态时 当前线程被其他线程中断时 上下文切换会带来额外的开销包括保存和恢复线程上下文信息的开销对线程进行调度的CPU时间开销以及CPU缓存内容失效(即CPU的L1 Cache、L2Cache等)的开销 线程状态 public enum State { // 新建的线程且还没有调用start方法启动 // new Thread() NEW, //运行状态等待CPU调度,包含了两个子状态READY和RUNNING // READY表示处于该状态的线程可以被JVM的线程调度器进行调度而使之处于RUNNING状态 // RUNNING表示线程已经获取了CPU正在运行 // 调用start方法 // yield方法 RUNNING-READY // 被synchronized标记的代码获取同步监视器 // obj.notify()/obj.notifyAll()唤醒线程 // obj.wait(time)、thread.join(time)等待时间耗尽 RUNNABLE, // 阻塞 等待获取synchronized同步块的对象锁或者调用wait方法之后重新进入synchronized同步块 BLOCKED, // 等待 // 调用Object.wait、Thread.join、LockSupport.park方法会进入等待状态 // WAITING-RUNNABLE 需要调用notify、notifyAll或者等待调用Thread.join的终止 WAITING, // 调用Thread.sleep、Object.wait(long)、Thread.join(long)、LockSupport.parkNanos、LockSupport.parkUntil这种等待超时 TIMED_WAITING, // 线程完成工作 // 1.run方法执行完毕正常退出 2.没有捕获异常导致run方法意外终止 TERMINATED;} 线程状态变化 https://zhhll.icu/2020/多线程/基础/1.线程简介/ 本文由 mdnice 多平台发布