网站开发的合同编写,长沙好的网站建设公司排名,网店托管代运营公司,wordpress wowslider一、Thread类
1、线程的创建
大家都熟知创建单个线程的三种方式#xff0c;通过继承Thread类创建线程并重写该类的run()方法#xff1b;通过实现Runnable接口创建线程一样要重写run()方法#xff1b;以上的两个run()方法都是线程的执行体#xff1b;第三#xff0c;使用…一、Thread类
1、线程的创建
大家都熟知创建单个线程的三种方式通过继承Thread类创建线程并重写该类的run()方法通过实现Runnable接口创建线程一样要重写run()方法以上的两个run()方法都是线程的执行体第三使用Callable和Future来创建线程Callable接口提供了一个call()方法来作为线程的执行体call()方法比run()方法功能要更加强大call()方法可以有返回值call()方法可以声明抛出异常前两种如果要抛异常只能通过try,catch来实现下面详细介绍一下Callable和Future
我们知道创建线程最终要由操作系统支持java中只有调掉Thread对象最后执行一个叫private native void start0();的本地方法而该方法的最终实现在C和C层面要阅读JVM源码才能更深一步暂时咱们知道最后是由操作系统给我们另起了一个线程取执行 “执行体”里面的业务。我们看Thread类的构造方法里面没有直接传Callable接口的构造方法那为啥我们还能运行下面这段代码呢 /*** Callable需要配合FutureTask使用* FutureTask的get()可以返回任务的执行结果方便在2个线程之间把一个线程的结果传给另一个线程** throws InterruptedException* throws ExecutionException*/private static void testFutureAndCallable() throws InterruptedException, ExecutionException {FutureTaskInteger future new FutureTask(() - {log.debug(running.....);Thread.sleep(1000);return 100;});Thread t3 new Thread(future, t3);t3.start();// 当主线程运行到get方法时主线程会阻塞住一直等待 t1线程 结果返回log.debug(main接收future的返回值{},future.get());log.debug(main线程继续运行....);}
我们可以看到直接把future对象传入给了Thread构造方法其实我们可以从FureTask出发 FutureTask实现了RunnableFuture接口而RunnableFuture又同时实现了Runnable和Future接口所以在直接构造Thread时可以直接传入构造参数执行。
public class FutureTaskV implements RunnableFutureV {}public interface RunnableFutureV extends Runnable, FutureV {} 尽管FureTaskCallable有返回值可以抛异常可以查看线程执行任务的情况但是有时候为获取它的返回值主线程而陷入阻塞等待另一个isDone()方法轮询获取值容易耗CPU资源.........
针对以上2个痛点JDK做了扩展CompletableFuture类同时实现了Future和CompletionStage接口在CompletionStage上做了极大的扩展 Runnable——没有输入参数也没有返回值 Function——功能型函数接口有一个参数有一个返回参数 Consumer——消费型函数接口有一个输入参数没有返回参数 —Consumer延申BiConsumer有两个输入参数没有返回参数 Supplier——供给型函数接口没有输入参数有返回值 数式接口名称方法名称参数返回值Runnablerun无参数无返回值Functionapply1个参数有返回值Consumeraccept1个参数无返回值Supplierget无参数有返回值BiConsumeraccept2个参数 无返回值 2、interrupt()、interrupted()、isinterrupted() public void interrupt() 实例方法 Just to set the interrupt flag 实例方法interrupt()仅仅是设置线程的中断状态为true发起一个协商而不会立刻停止线程。 如果线程处于被阻塞状态例如处于sleepwaitjoin等状态在别的线程中调用当前线程对象的interrupt方法那么线程将立即退出被阻塞状态并抛出一个InterruptException异常。 public static boolean interrupted() 静态方法Thread.interrupted(); 判断线程是否被中断并清除当前中断状态。 这个方法做了两件事 1.返回到当前线程的中断状态测试当前线程是否已被中断。 2.将当前线程的中断状态清零并重新设为false清除线程的中断状态 public boolean isInterrupted() 实例方法 判断当前线程是否被中断通过检查中断标志位 二、Java的锁 乐观锁 1、版本号version 2、CAS(compareAndSwap)算法java原子类(Atomic打头的类)中的递增操作就是通过CAS自旋实现的。——Unsafe类 使用场景适合读操作多的场景不加锁的特点能够使其读取操作的性能大幅提升。乐观锁则直接去操作同步资源是一种无锁算法 悲观锁 同一时间点有且仅有一个线程占有锁 1、synchronized 2、ReentrantLock 使用场景适合写操作多的场景先加锁可以保证写操作时数据正确现实的锁定之后在操作同步资源 1、synchronized 为什么任何一个对象都可以成为一把锁
因为Java中所有的对象都默认继承了超类Object而Object在JVM源码(C)层面关联了一个对象ObjectMonitor所以每个对象“天生”都带着一个对象监视器也就是每一个被锁住的对象都会和Monitor关联起来。 ObjectMonitor中有几个关键属性
_owner指向持有ObjectMonitor对象的线程_WaitSet存放于wait状态的线程队列_EntryList存放处于等待锁block状态的线程队列_recursious锁的重入次数_count用来记录该线程获取锁的次数 管程Monitors也叫监视器
是一种程序结构结构内的多个子程序对象或模块形成的多个工作线程互斥访问共享资源。这些共享资源一般是硬件设备或一群变量。对共享变量能够进行的所有操作集中在一个模块中。把信号量及其操作原语“封装”在一个对象内部管程实现了在一个时间点最多只有一个线程在执行管程的某个子程序。管程提供了一种机制管程可以看作一个软件模块它是将共享的变量和对于这些共享变量的操作封装起来形成一个具有一定接口的功能模块进程可以调用管程来实现进程级别的并发控制。
注synchronized和 static synchronized前者是对象锁后者是类锁属于不同的锁a线程加对象锁b线程加类锁加锁不同a、b线程不会产生竟态条件。 2、自旋锁
没有成员变量的类一般都是线程安全的 cynchronized 并发压测工具 装饰器模式Collections以synchronized打头的的实现集合的那些方法就是采用了装饰器模式。
1、AQS
AQS全称是AbstractQueuedSynchronizer是阻塞式锁和相关的同步器工具的框架
特点
1、用state属性来表示资源的状态分独占模式和共享模式子类需要定义如何维护这个状态控制如何获取锁和释放锁
—getState-获取state状态
—setState-设置state状态
—compareAndSetState-cas机制设置state状态[compare式保证state的原子性]
2、提供了基于FIFO的等待队列类似于Monitor的EntryList
3、条件变量来实现等待、唤醒机制支持多个条件变量类似于Montor的WaitSet