当前位置: 首页 > news >正文

网站流量下滑做logo的网站

网站流量下滑,做logo的网站,墙外必去的网站,福州营销型网站建设1.创建线程三种方式 Runnable.Callable接口使用继承Thread类的方式创建多线程Runnable 和Callable区别 Callable规定#xff08;重写#xff09;的方法是call()#xff0c;Runnable规定#xff08;重写#xff09;的方法是run()。Callable的任务执行后可返回值#xff0…1.创建线程三种方式 Runnable.Callable接口使用继承Thread类的方式创建多线程Runnable 和Callable区别 Callable规定重写的方法是call()Runnable规定重写的方法是run()。Callable的任务执行后可返回值而Runnable的任务是不能返回值的。Call方法可以抛出异常run方法不可以。运行Callable任务可以拿到一个Future对象表示异步计算的结果。它提供了检查计算是否完成的 方法以等待计算的完成并检索计算的结果。通过Future对象可以了解任务执行情况可取消任 务的执行还可获取执行结果 start 和 run 调用 start 方法方可启动线程并使线程进入就绪状态而 run 方法只是 thread 的一个普通方法调用还是在主线程里执行。JVM执行start方法会另起一条线程执行thread的run方法这才起到多线程的效果~ 如果直接调用Thread的run()方法其方法还是运行在主线程中没有起到多线程效果 1 start 方法 用 start 方法来启动线程真正实现了多线程运行。通过调用 Thread 类的 start()方法来启动一个线程这时此线程处于就绪可运行状态并没有 运行一旦得到 cpu 时间片就开始执行 run()方法这里方法 run()称为线 程体它包含了要执行的这个线程的内容Run 方法运行结束此线程随即 终止。 2 run run()方法只是类的一个普通方法而已如果直接调用 run 方法程序 中依然只有主线程这一个线程其程序执行路径还是只有一条还是要顺序 执行还是要等待run 方法体执行完毕后才可继续执行下面的代码这样 就没有达到写线程的目的。 总结调用 start 方法方可启动线程而 run 方法只是 thread 的一个 普通方法调用还是在主线程里执行。这两个方法应该都比较熟悉把需要 并行处理的代码放在 run()方法中start()方法启动线程将自动调用 run() 方法这是由 jvm 的内存机制规定的。并且 run()方法必须是 public 访问权 限返回值类型为 void。 两种方式的比较 实际中往往采用实现 Runable 接口一方面因为 java 只支持单继承 继承了 Thread 类就无法再继续继承其它类而且 Runable 接口只有一个 run 方法另一方面通过结果可以看出实现 Runable 接口才是真正的多线程。 2.线程的状态流转 新建状态线程对象创建后即进入了新建状态Thread t new MyThread就绪状态当调用线程对象的start()方法t.start();线程即进入就绪状态。处于就绪状态的线程已经做好了准备随时等待CPU调度执行并不是说执行了t.start()此线程立即就会执行运行状态当CPU开始调度处于就绪状态的线程时此时线程才得以真正执行即进入到运行状态。注就 绪状态是进入到运行状态的唯一入口也就是说线程要想进入运行状态执行首先必须处于就绪状态中阻塞状态处于运行状态中的线程由于某种原因暂时放弃对CPU的使用权停止执行此时进入阻塞状态直到其进入到就绪状态才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同阻塞状态又可以分为三种 等待阻塞运行状态中的线程执行wait()方法使本线程进入到等待阻塞状态同步阻塞 — 线程在获取synchronized同步锁失败(因为锁被其它线程所占用)它会进入同步阻塞状态其他阻塞 — 通过调用线程的sleep()或join()或发出了I/O请求时线程会进入到阻塞状态。当sleep()状态超时. join()等待线程终止或者超时. 或者I/O处理完毕时线程重新转入就绪状态。 死亡状态线程执行完了或者因异常退出了run()方法该线程结束生命周期 3.死锁 条件互斥条件、请求保持、不剥夺条件、循环等待条件避免死锁 破坏请求与保持条件一次性申请所有资源破坏不剥夺条件占用部分资源的线程进一步申请其他资源时如申请不到可以主动释放它占有的资源破坏循环等待条件靠按序申请资源来预防。按某一顺序申请资源释放资源则反序释放。破坏循环等待条件。锁排序法规定只有获得A锁的线程才有资格获取B锁按顺序获取锁就可以避免死锁。使用显示锁中的ReentrantLock.trylongTimeUnit来申请锁 4.shutdown() VS shutdownNow() shutdown :关闭线程池线程池的状态变为 SHUTDOWN。线程池不再接受新任务了但是队 列里的任务得执行完毕。shutdownNow :关闭线程池线程的状态变为 STOP。线程池会终止当前正在运行的任务并 停止处理排队的任务并返回正在等待执行的 List。 原理:遍历线程池中的工作线程逐个调用线程的interrupt方法中断线程所以无法响应中断的任务可能永远无法终止 5.isTerminated() VS isShutdown() isShutDown 当调用 shutdown() 方法后返回为 true。isTerminated 当调用 shutdown() 方法后并且所有提交的任务完成后返回为 true 6.sleep() 和 wait() 区别 sleep方法是Thread类的静态方法当前线程将睡眠n毫秒线程进入阻塞状态。当睡眠时间到了会解除阻塞进入可运行状态等待CPU的到来。睡眠不释放锁如果有的话。wait方法是Object的方法必须与synchronized关键字一起使用线程进入阻塞状态当notify或者notifyall被调用后会解除阻塞。但是只有重新占用互斥锁之后才会进入可运行状态。睡眠时会释放互斥锁。sleep 方法没有释放锁而 wait 方法释放了锁 。sleep 通常被用于暂停执行Wait 通常被用于线程间交互/通信sleep() 方法执行完成后线程会自动苏醒。或者可以使用 wait(long timeout)超时后线程会自动苏醒。wait() 方法被调用后线程不会自动苏醒需要别的线程调用同一个对象上的 notify() 或者notifyAll() 方法 相同 两者都可以暂停线程的执行 7.yield Yield方法可以暂停当前正在执行的线程对象让其它有相同优先级的线程执行。静态方法而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU执行yield()的线程有可能在进入到暂停状态后马上又被执行。 8.volatile 语义 volatile保证变量对所有线程的可见性当volatile变量被修改新值对所有线程会立即更新。或者 理解为多线程环境下使用volatile修饰的变量的值一定是最新的。jdk1.5以后volatile完全避免了指令重排优化实现了有序性。 原理: 获取JIT即时Java编译器把字节码解释为机器语言发送给处理器的汇编代码发现volatile多加了 lock addl指令这个操作相当于一个内存屏障使得lock指令后的指令不能重排序到内存屏障前的位 置。这也是为什么JDK1.5以后可以使用双锁检测实现单例模式。lock前缀的另一层意义是使得本线程工作内存中的volatile变量值立即写入到主内存中并且使得其他线 程共享的该volatile变量无效化这样其他线程必须重新从主内存中读取变量值。 9.线程阻塞三种情况 等待阻塞Object.wait-等待队列running状态的线程执行object.wait方法后jvm会将线程放入等待序列同步阻塞lock-锁池running状态的线程在获取对象的同步锁时若该同步锁被其他线程占用则jvm将该线程放入锁池中其他阻塞sleep/joinrunning状态的线程执行Thread.sleeplong ms或发出i/o请求时jvm会将该线程置为阻塞状态当sleep状态超时join等待线程终止或超时或者i/o处理完毕时线程重新转入可运行状态 10.线程死亡三种方式 正常结束run或call()方法执行完成后线程正常结束异常结束线程抛出一个未捕获的exception 或error导致线程异常结束调用stop直接调用线程的stop方法来结束该线程会导致死锁一般不推荐 11.守护线程 运行在后台的一种特殊进程。独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在 Java 中垃圾回收线程就是特殊的守护线程。 12.fork/jion Fork/Join框架是Java7提供的一个用于并行执行任务的框架是一个把大任务分割成若干个小任务最终汇总每个小任务结果后得到大任务结果的框架。 Fork/Join框架需要理解两个点「分而治之」和「工作窃取算法」。 「分而治之」以上Fork/Join框架的定义就是分而治之思想的体现啦 「工作窃取算法」把大任务拆分成小任务放到不同队列执行交由不同的线程分别执行时。有的线程优先把自己负责的。任务执行完了其他线程还在慢慢悠悠处理自己的任务这时候为了充分提高效率就需要工作盗窃算法啦~ 工作盗窃算法就是「某个线程从其他队列中窃取任务进行执行的过程」。一般就是指做得快的线 程盗窃线程抢慢的线程的任务来做同时为了减少锁竞争通常使用双端队列即快线程和慢线程 各在一端 13.cas–Compare and swap 即比较并交换 一条 CPU 同步原语。是一种硬件对并发的支持针对多处理器操作而设计的一种特殊指令用于管理对共享数据的并发访问。CAS 是一种无锁的非阻塞算法的实现。CAS 包含了 3 个操作数 需要读写的内存值 V旧的预期值 A要修改的更新值 B 当且仅当 V 的值等于 A 时CAS 通过原子方式用新值 B 来更新 V 的 值否则不会执行任何操作他的功能是判断内存某个位置的值是否为预期值如果是则更改为新的值这个过程是原子的。缺陷 ABA 问题AtomicStampedReference可以解决ABA问题一个带有标记的原子引用类通过控制变量值的版本来保证CAS的正确性。循环时间长开销CAS是有个自旋次数的就是为了避开这个耗时问题只能保证一个变量的原子操作。 保证的是对一个变量执行操作的原子性如果对多个变量操作时CAS 目前无法直接保证操作的原子性的。 解决 使用互斥锁来保证原子性将多个变量封装成对象通过AtomicReference来保证原子性 14.synchronized 和 volatile volatile 解决的是内存可见性问题使得所有对 volatile 变量的读写都直接写入主存保证了变量的可见性。synchronized 解决的是执行控制的问题它会阻止其他线程获取当前对象的监控锁当前对象中被 synchronized 关键字保护的代码块无法被其他线程访问也就是无法并发执行。synchronized 还会创建一个 内存屏障内存屏障指令保证了所有 CPU 操作结果都会直接刷到主存中从而保证操作的内存可见性同时也使得这个锁的线程的所有操作都 happens-before 于随后获得这个锁的线程的操作。区别 volatile 本质是在告诉 JVM 当前变量在寄存器工作内存中的值是不确定的需要从主存中读取 synchronized 则是锁定当前变量只有当前线程可以访问该变量其他线程被阻塞住。volatile 仅能使用在变量级别synchronized 则可以使用在变量. 方法.和类级别的volatile 仅能实现变量的修改可见性不能保证原子性而synchronized 则可以保证变量的修改可见性和原子性volatile 不会造成线程的阻塞synchronized 可能会造成线程的阻塞。volatile 标记的变量不会被编译器优化synchronized 标记的变量可以被编译器优化。 15.synchronized 和 Lock synchronized 可以给类. 方法. 代码块加锁而 lock 只能给代码块加锁。synchronized 不需要手动获取锁和释放锁使用简单发生异常会自动释放锁不会造成死锁 而 lock 需要自己加锁和释放锁如果使用不当没有 unLock()去释放锁就会造成死锁。通过 Lock 可以知道有没有成功获取锁而 synchronized 却无法办到 16.synchronized 和 ReentrantLock 两者都是可重入锁 可重入锁指的是在一个线程中可以多次获取同一把锁比如一个线程在执行一个带锁的方法该方法中又调用了另一个需要相同锁的方法则该线程可以直接执行调用的方法而无需重新获得锁两者都是同一个线程每进入一次锁的计数器都自增1所以要等到锁的计数器下降为0时才能释放锁。 synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API synchronized 是依赖于 JVM 实现的虚拟机团队在 JDK1.6 为 synchronized 关键字进行了很多优化但是这些优化都是在虚拟机层面实现的ReentrantLock 是 JDK 层面实现的需要 lock() 和 unlock() 方法配合 try/finally语句块来完成 ReentrantLock 比 synchronized 增加了一些高级功能 相比synchronizedReentrantLock增加了一些高级功能。①等待可中断通过lock.lockInterruptibly()来实现这个机制。正在等待的线程可以选择放弃等待改为处理其他事情。②可实现公平锁ReentrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。 ReentrantLock默认情况是非公平的可以通过 ReentrantLock类的ReentrantLock(boolean fair)构造方法来制定是否是公平的。③可实现选择性通知锁可以绑定多个条件ReentrantLock类线程对象可以注册在指定的Condition中从而可以有选择性的进行线程通知在调度线程上更加灵活。 在使用notify()/notifyAll()方法进行通知时被通知的线程是由 JVM 选择的用ReentrantLock类结合Condition实例可以实现“选择性通知” 使用选择 除非需要使用 ReentrantLock 的高级功能否则优先使用 synchronized。 synchronized 是 JVM 实现的一种锁机制JVM 原生地支持它而 ReentrantLock 不是所有的 JDK版本都支持。并且使用 synchronized 不用担心没有释放锁而导致死锁问题因为 JVM 会确保锁的释放 17.synchronized 用法 修饰普通方法:作用于当前对象实例进入同步代码前要获得当前对象实例的锁修饰静态方法:作用于当前类进入同步代码前要获得当前类对象的锁,synchronized 关键字加到 static 静态方法和 synchronized(class)代码块上都是是给 Class 类上锁修饰代码块:指定加锁对象对给定对象加锁进入同步代码库前要获得给定对象的锁特别注意 ① 如果一个线程A调用一个实例对象的非静态 synchronized 方法而线程B需要调用这个实例对象所属类的静态 synchronized 方法是允许的不会发生互斥现象因为访问静态 synchronized 方法占用的锁是当前类的锁② 尽量不要使用 synchronized(String s) ,因为JVM中字符串常量池具有缓冲功能 作用 原子性确保线程互斥的访问同步代码可见性保证共享变量的修改能够及时可见其实是通过Java内存模型中的 “对一个变量unlock操作之前必须要同步到主内存中如果对一个变量进行lock操作则将会清空工作内存中此变量的值在执行引擎使用此变量前需要重新从主内存中load操作或assign操作初始化变量值” 来保证的有序性有效解决重排序问题即 “一个unlock操作先行发生(happen-before)于后面对同一个锁的lock操作”。 底层实现原理 synchronized 同步代码块的实现是通过 monitorenter 和 monitorexit 指令 monitorenter 指令指向同步代码块的开始位置monitorexit 指令则指明同步代码块的结束位置。 当执行 monitorenter 指令时线程试图获取锁即获取 monitor的持有权。(monitor对象存在于每个Java对象的对象头中synchronized 锁便是通过这种方式获取锁的也是为什么Java中任意对象可以作为锁的原因) 。其内部包含一个计数器当计数器为0则可以成功获取获取后将锁计数器设为1也就是加1。相应的在执行 monitorexit 指令后将锁计数器设为0表明锁被释放。如果获取对象锁失败那当前线程就要阻塞等待直到锁被另外一个线程释放为止synchronized 修饰的方法是ACC_SYNCHRONIZED 标识该标识指明了该方法是一个同步方法JVM 通过该 ACC_SYNCHRONIZED。访问标志来辨别一个方法是否声明为同步方法从而执行相应的同步调用。 synchronized 锁升级的原理 在锁对象的对象头里面有一个 threadid 字段第一次访问时threadid 为空jvm 让其持有偏向锁并将 threadid 设置为其线程 id再次进入时会先判断threadid 是否与其线程 id 一致 一致。则可以直接使用此对象不一致则升级偏向锁为轻量级锁通过自旋循环一定次数来获取锁执行一定次数之后如果还没有正常获取到要使用的对象把锁从轻量级升级为重量级锁此过程构成了 synchronized 锁的升级。 锁升级目的为了减低了锁带来的性能消耗。在 Java 6 之后优化 synchronized 的实现方式使用了偏向锁升级为轻量级锁再升级到重量级锁的方式从而减低了锁带来的性能消耗 synchronized 非公平锁 当持有锁的线程释放锁时该线程会执行以下两个重要操作 先将锁的持有者 owner 属性赋值为 null唤醒等待链表中的一个线程假定继承者。在1和2之间如果有其他线程刚好在尝试获取锁例如自旋则可以马上获取到锁。 当线程尝试获取锁失败进入阻塞时放入链表的顺序和最终被唤醒的顺序是不一致的也就是说你先进入链表不代表你就会先被唤醒。 jvm对synchronized 的优化 锁膨胀膨胀方向是无锁——偏向锁——轻量级锁——重量级锁并且膨胀方向不可逆。 偏向锁减少统一线程获取锁的代价。多数情况下锁不存在多线程竞争总是由同一线程多次获得此时就是偏向锁。 核心思想如果一个线程获得了锁那么锁就进入偏向模式此时 Mark Word 的结构也就变为偏向锁结构当该线程再次请求锁时无需再做任何同步操作即获取锁的过程只需要检查 Mark Word 的锁标记位为偏向锁以及当前线程ID等于 Mark Word 的ThreadID即可省去了大量有关锁申请的操作。 轻量级锁由偏向锁升级而来当存在第二个线程申请同一个锁对象时偏向锁就会立即升级为轻量级锁。这里的第二个线程只是申请锁不存在两个线程同时竞争锁可以是一前一后地交替执行同步块。重量级锁由轻量级锁升级而来同一时间有多个线程竞争锁时锁就会被升级成重量级锁此时其申请锁带来的开销也就变大。重量级锁一般使用场景会在追求吞吐量同步块或者同步方法执行时间较长的场景。 锁消除虚拟机另外一种锁的优化在JIT编译时对运行上下文进行扫描去除不可能存在竞争的锁。object锁是私有变量不存在所得竞争关系。 锁粗化虚拟机另一种优化处理通过扩大锁的范围避免反复加锁和释放锁。 自旋锁与自适应自旋锁轻量级锁失败后虚拟机为了避免线程真实地在操作系统层面挂起进行自旋锁的优化手段。 自旋锁许多情况下共享数据的锁定状态持续时间较短切换线程不值得通过让线程执行循环等待锁的释放不让出CPU。如果得到锁就顺利进入临界区。如果还不能获得锁那就会将线程在操作系统层面挂起这就是自旋锁的优化方式。 缺点如果锁被其他线程长时间占用一直不释放CPU会带来许多的性能开销。 自适应自旋锁相当于是对自旋锁优化方式的进一步优化它的自旋的次数不再固定其自旋的次数由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定这就解决了自旋锁带来的缺点。 为什么要引入偏向锁和轻量级锁为什么重量级锁开销大 重量级锁底层依赖于系统的同步函数来实现在 linux 中使用 pthread_mutex_t互斥锁来实现。这些底层的同步函数操作会涉及到操作系统用户态和内核态的切换、进程的上下文切换而这些操作都是比较耗时的因此重量级锁操作的开销比较大。 很多情况下可能获取锁时只有一个线程或者是多个线程交替获取锁在这种情况下使用重量级锁就不划算了因此引入了偏向锁和轻量级锁来降低没有并发竞争时的锁开销。 synchronized锁能降级么 可以。触发时机在全局安全点safepoint中执行清理任务的时候会触发尝试降级锁操作 恢复锁对象的 markword 对象头重置 ObjectMonitor然后将该 ObjectMonitor 放入全局空闲列表等待后续使用 18.ThreadLocal 线程本地变量如果创建了一个ThreadLocal变量那么访问这个变量的每个线程都会有这个变量的一个本地拷贝多个线程操作这个变量的时候实际是操作自己本地内存里面的变量从而起到线程隔离的作用避免了线程安全问题。 应用场景 数据库连接池会话管理中使用 实现原理 Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals即每个线程都有一个属于自己的ThreadLocalMap。ThreadLocalMap内部维护着Entry数组每个Entry代表一个完整的对象key是ThreadLocal本身value是ThreadLocal的泛型值。每个线程在往ThreadLocal里设置值的时候都是往自己的ThreadLocalMap里存读也是以某个ThreadLocal作为引用在自己的map里找对应的key从而实现了线程隔离。 内存泄露问题 ThreadLocalMap中使用的 key 为 ThreadLocal 的弱引用 只要垃圾回收机制一运行不管JVM的内存空间是否充足都会回收该对象占用的内存 ThreadLocalMap生命周期和Thread是一样的它这时候如果不被回收就会出现ThreadLocalMap的key没了value还在这就会「造成了内存泄漏问题」。解决使用完ThreadLocal后及时调用remove()方法释放内存空间。 19.ReentrantLock ReetrantLock是一个可重入的独占锁支持公平锁和非公平锁可重入。ReetrantLock实现依赖于AQS(AbstractQueuedSynchronizer)。ReetrantLock主要依靠AQS维护一个阻塞队列多个线程对加锁时失败则会进入阻塞队列。等待唤醒重新尝试加锁。 20.ReadWriteLock 使用ReentrantLock可能本身是为了防止线程A在写数据、线程B在读数据造成的数据不一致。但如果线程C在读数据、线程D也在读数据读数据是不会改变数据的没有必要加锁但是还是加锁了降低了程序的性能。读写锁ReadWriteLock。ReadWriteLock是一个读写锁接口ReentrantReadWriteLock是ReadWriteLock接口的一个具体实现实现了读写的分离读锁是共享的写锁是独占的读和读之间不会互斥读和写、写和读、写和写之间才会互斥提升了读写的性能 1.现在有T1,T2,T3三个线程怎样保证T2在T1执行完成后执行T3在T2执行完后执行 在线程B中调用了线程A的Join()方法直到线程A执行完毕后才会继续执行线程B。 join()方法的作用就是让主线程等待子线程执行结束之后再运行主线程。 thread.Join把指定的线程加入到当前线程可以将两个交替执行的线程合并为顺序执行的线程。 比如在线程B中调用了线程A的Join()方法直到线程A执行完毕后才会继续执行线程B。 使用场景线程2依赖于线程1执行的返回结果 public static void main(String[] args) throws Exception{Thread t1 new Thread(()-{try {Thread.sleep(500);System.out.println(线程1醒了);} catch (InterruptedException e) {e.printStackTrace();}for(int i0;i100;i){System.out.println(线程1 i:i);}});t1.setName(线程1);Thread t2 new Thread(()-{try {t1.join();} catch (InterruptedException e) {e.printStackTrace();}for(int i0;i100;i){System.out.println(线程2 i:i);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}});t2.setName(线程2);t2.start();t1.start(); }2.在 Java 中 Lock 接口比 synchronized 块的优势是什么你需要实现一个高效的缓存它允 许多个用户读但只允许一个用户写以此来保持它的完整性你会怎样去实现它 lock 接口在多线程和并发编程中最大的优势是它们为读和写分别提供了锁它能满足你写像 ConcurrentHashMap 这样的高性能数据结构和有条件的阻塞。 区别 1、lock是一个接口而synchronized是java的一个关键字。2、synchronized在发生异常时会自动释放占有的锁因此不会出现死锁而lock发生异常时不会主动释放占有的锁必须手动来释放锁可能引起死锁的发生。 synchronized Java中每一个对象都可以作为锁这是synchronized实现同步的基础 普通同步方法锁是当前实例对象静态同步方法锁是当前类的class对象同步方法块锁是括号里面的对象 public class SynchronizedTest {public synchronized void test1(){} public void test2(){ synchronized (this){}} }javap工具可以查看生成的class文件信息来分析Synchronized的实现 同步代码块是使用monitorenter和monitorexit指令实现的 通过在对象头设置标记达到获取锁和释放锁的目的。 monitorenter指令是在编译后插入到同步代码块的开始位置monitorexit指令插入到同步代码块的结束位置JVM需要保证每一个monitorenter都有一个monitorexit与之相对应。任何对象都有一个monitor与之相关联当且一个monitor被持有之后他将处于锁定状态。 线程执行到monitorenter指令时将会尝试获取对象所对应的monitor所有权即尝试获取对象的锁。获取锁锁的计数器1 线程执行到monitorexit指令时锁计数器-1计数器为0时锁被释放。 获取对象失败当前线程阻塞等待直到对象锁被另一个线程释放为止。 同步方法在这看不出来需要看JVM底层实现依靠的是方法修饰符上的ACC_SYNCHRONIZED实现。 synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令在VM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法而是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位置1表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示Klass做为锁对象。 区别 来源 lock是一个接口而synchronized是java的一个关键字synchronized是内置的语言实现异常是否释放锁 synchronized在发生异常时候会自动释放占有的锁因此不会出现死锁而lock发生异常时候不会主动释放占有的锁必须手动unlock来释放锁可能引起死锁的发生。所以最好将同步代码块用try catch包起来finally中写入unlock避免死锁的发生。是否响应中断 lock等待锁过程中可以用interrupt来中断等待而synchronized只能等待锁的释放不能响应中断是否知道获取锁 Lock可以通过trylock来知道有没有获取锁而synchronized不能Lock可以提高多个线程进行读操作的效率。可以通过readwritelock实现读写分离在性能上来说如果竞争资源不激烈两者的性能是差不多的而当竞争资源非常激烈时即有大量线程同时竞争此时Lock的性能要远远优于synchronized。所以说在具体使用时要根据适当情况选择。synchronized使用Object对象本身的wait 、notify、notifyAll调度机制而Lock可以使用Condition进行线程之间的调度 //Condition定义了等待/通知两种类型的方法 Lock locknew ReentrantLock(); Condition conditionlock.newCondition();...condition.await();...condition.signal(); condition.signalAll();使用 synchronized在需要同步的对象中加入此控制synchronized可以加在方法上也可以加在特定代码块中括号中表示需要锁的对象。 lock一般使用ReentrantLock类做为锁。在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。 2种机制的具体区别 **synchronized原始采用的是CPU悲观锁机制即线程获得的是独占锁。**独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换当有很多线程竞争锁的时候会引起CPU频繁的上下文切换导致效率很低。 而Lock用的是乐观锁方式。所谓乐观锁就是每次不加锁而是假设没有冲突而去完成某项操作如果因为冲突失败就重试直到成功为止。乐观锁实现的机制就是CAS操作Compare and Swap。其中比较重要的获得锁的一个方法是compareAndSetState。调用的CPU提供的特殊指令。可以自动更新共享数据而且能够检测到其他线程的干扰而 compareAndSet() 就用这些代替了锁定。这个算法称作非阻塞算法意思是一个线程的失败或者挂起不应该影响其他线程的失败或挂起的算法。 3.在 java 中 wait 和 sleep 方法的不同 sleep使线程暂停执行一算时间的方法。 wait使线程暂停一段时间的方法。例如当线程进行交互时如果线程对一个同步对象x发出一个wait调用请求那么该线程会暂停执行被调用对象进入等待状态直到被唤醒或者等待时间超时。 原理不同: sleep方法属于Thread类的静态方法是线程用来控制自身流的它会使此线程暂停执行一段时间而把执行时间让给其他的线程等倒计时时间一到此线程会自动苏醒。wait方法属于Object类的方法用于线程间的通信会使当前拥有该对象锁的进程处于等待的状态直到其他线程调用notify方法或者notifyAll时才会苏醒可以给它制定一个时间自动“醒”来。 对锁的处理机制不同: sleep方法的主要作用是让线程暂停一段时间执行时间一到则自动恢复不涉及线程间的通信调用sleep不会释放锁。wait方法则不同当调用wait方法后线程会释放掉它所占有的锁从而使线程所在对象中的其他synchronized数据可被别的线程使用。 使用区域不同: wait方法的意义比较特殊因此 他必须放在同步控制方法或者同步语句块中使用而sleep方法则可以在任何的地方使用。sleep方法必须捕获异常而wait、notify、notifyAll部需要捕获异常。在sleep过程中有可能被其他对象调用它的interrupt方法产生InnterruptException异常。 由于sleep方法不会释放“锁标志”容易造成死锁的问题发生因此在一般情况下不推荐使用sleep方法而推荐使用wait方法 slepp方法与yield方法有什么区别 1sleep方法给其他线程运行机会时不考虑线程的优先级因此会给低优先级的线程运行的机会。而yield方法只会给相同的优先级或者更高优先级的线程以运行的机会。 2线程执行sleep方法后会转入阻塞状态所以执行sleep方法的线程在指定的时间内肯定不会被执行。而yield方法只是使当前线程重回到可执行状态所以执行yeild方法的线程有可能在进入到可执行状态后马上又被执行。 3sleep方法声明抛出InterruptException而yeild方法没有声明任何异常。 4sleep方法比yield方法跟操作系统相关具有更好的可移植性。 7.什么是原子操作 Java 中的原子操作是什么 原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始就一直运行到结束中间切换到另一个线程。 java.util.concurrent.atomic 包里面提供了一组原子类。基本特性就是在多线程环境下当有多个线程同时执行这些类的实例包含的方法时具有排他性。即当某个线程进入方法执行其中的指令时不会被其他线程打断而别的线程就像锁一样一直等到该方法执行完成才由JVM从等待队列中选择另一个线程进入这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的但不会阻塞线程(synchronized 会把别的等待的线程挂或者说只是在硬件级别上阻塞了)。 8.Java 中的 volatile 关键是什么作用怎样使用它在 Java 中它跟 synchronized 方法有什么不同 volatile是轻量级的synchronized其在多处理器开发中保证了共享变量的“可见性”。 可见性当一个线程修改一个共享变量时另外一个线程能读到这个修改的值。 一个变量被定义成volatile后具备两种特性 保证此变量对所有线程的可见性禁止指令重排序优化 内存模型定义了8种内存间操作 lock和unlock 把一个变量标识为一条线程独占状态把一个处于锁定状态的变量释放出来释放之后的变量才能被其他线程锁定 read和write 把一个变量值从主内存传输到线程的工作内存以便load把store操作从工作内存得到的变量的值放入主内存的变量中 load和store 把read操作从主内存得到的变量值放入工作内存的变量副本中把工作内存的变量值传送到主内存中以便write use和assgin 把工作内存变量值传递给执行引擎将执行引擎值传递给工作内存变量值 volatile是不是并发安全的 不是volatile变量在各个线程的工作内存不存在一致性问题但运算并非原子操作。 Java代码需要转化为汇编指令在CPU上运行。有volatile变量修饰的共享变量进行写操作的时候会多出第二行汇编代码第二行汇编代码中包含有Lock前缀。 Lock前缀的指令在多核处理器下会引发了两件事 1.将当前处理器缓存行的数据写回到系统内存。 2.这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。 原本处理器会将系统内存的数据读到内部缓存后进行操作但操作完不知道何时会写到内存。所以当多线程并发的时候其他处理器缓存的值还是旧的再执行计算操作就会有问题。 而加上了volatile关键字对变量进行写操作时JVM就会向处理器发送一条Lock前缀的指令将这个变量所在缓存行的数据写回到系统内存。这样每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了当处理器发现自己缓存行对应的内存地址被修改就会将当前处理器的缓存行设置成无效状态当处理器对这个数据进行修改操作的时候会重新从系统内存中把数据读到处理器缓存里。 两大原则 1.Lock前缀指令会引起处理器缓存回写到内存。Lock前缀指令导致在执行指令期间声言处理器的LOCK#信号。在多处理器环境中LOCK#信号确保在声言该信号期间处理器可以独占任何共享内存 2.一个处理器的缓存回写到内存会导致其他处理器的缓存无效。处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存的数据在总线上保持一致。 sychronized 悲观锁不管是否产生竞争都会加锁、非公平锁获取锁行为上不是按时间前后给等待线程分配锁的锁释放任何线程都有机会竞争到锁缺点产生线程饥饿、可重入锁获取锁1可重入锁最大的作用是避免死锁。 级别从低到高依次是无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级目的是为了提高获得锁和释放锁的效率。 成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入。 public synchronized void synMethod(){ //方法体 } 对某一代码块使用 synchronized后跟括号,括号里是变量一次只有一个线程进入该代码块此时,线程获得的是成员锁。 public Object synMethod(Object a1){ synchronized(a1){ //一次只能有一个线程进入 } } 如果synchronized后面括号里是一个对象,此时,线程获得的是对象锁。如果线程进入,则得到当前对象锁,那么其他没有获得锁的线程在该类所有对象上的任何操作都不能进行。 public classMyThread implements Runnable{ public static void main(Stringargs[]){ Thread t1newThread(mt,“t1”); Thread t2newThread(mt,“t2”); t1.start(); t2.start(); } public void run(){ synchronized(this){ System.out.println(Thread.currentThread().getName()); } } 如果synchronized后面括号里是类,此时线程获得的是对象锁。如果其他线程进入,则线程在该类中所有操作不能进行,包括静态变量和静态方法。实际上,对于含有静态方法和静态变量的代码块的同步,我们通常选用例4来加锁。 class ArrayWithLockOrder{  public ArrayWithLockOrder(int[]a){   synchronized(ArrayWithLockOrder.class){    //代码逻辑    }  }  } jvm对java原生锁的优化 ① 自旋锁把线程进行阻塞操作之前先让线程自旋等待一段时间可能在等待期间其他线程已经解锁这时无需让线程执行阻塞操作避免了用户态到内核态的切换 ②锁消除JVM对一些代码上要求同步但被检测到不可能存在共享数据竞争的锁进行消除主要根据逃逸分析。 ③锁粗化增大锁的作用域 synchronized和reentrantLock 实现原理有什么不同 锁的实现原理基本是为了达到一个目的让所有线程都能看到某种标记 synchronized对象头 reentrantLock及基于lock接口的实现类通过用一个volatile修饰的int型变量并保证每个线程都拥有对该int的可见性和原子修改本质是基于所谓的AQS框架。 public class RWSample {private final MapString, String m new TreeMap();private final ReentrantReadWriteLock rwl new ReentrantReadWriteLock();private final Lock r rwl.readLock();private final Lock w rwl.writeLock();public String get(String key){r.lock();System.out.println(读锁锁定);try {return m.get(key);} finally {r.unlock();}}public String put(String key, String entry){w.lock();System.out.println(写锁锁定);try {return m.put(key, entry);}finally {w.unlock();}}}AQS:一个用来构建锁和同步器的框架各种Lock包中的锁egReentrantLockReadWriteLockSemaphoreCountDownLatchFutureTask等。 同步状态volatile int state0没有任何线程占有共享资源的锁可以获得锁。1有线程目前正在使用共享变量其他线程必须加入同步的队列等待。 同步队列Node内部类构成的一个双向链表结构完成线程获取锁的排队工作当有线程获取锁失败后就被添加到队列末尾。 Node类包含线程本身及其状态waitStatus5种取值阻塞等待唤醒等每个node结点关联其prev结点 和next结点方便线程释放后快速唤醒下一个在等待的线程是一个FIFO过程。常量SHARED共享模式EXCLUSIVE(独占模式) ConditionObject:构建等待队列Condition调用wait()方法线程将会加入等待队列调用signal从等待队列转移到同步队列中进行锁竞争。 AQS和Condition各自维护了不同的队列在使用Lock和Condition的时候就是两个队列互相移动。 从功能角度ReetrantLock比Synchronized的同步操作更精细可以实现更多高级功能 等待可中断当持有锁的线程长期不释放锁的时候正在等待的线程可以选择放弃等待对处理执行时间非常长的同步块很有用。 带超时的获取锁尝试指定时间范围内没有获取则返回。 可以判断是否有线程在排队等待获取锁 可以响应中断请求中断异常会被抛出锁会被释放 可以实现公平锁 释放锁synchronized在jvm层面上实现发生异常时jvm会自动释放锁定lock通过代码实现要保证锁一定会被释放必须将unlock放到finally中。 性能 竞争不激烈时synchronized性能要优于ReetrantLock 高竞争时synchronized性能会下降几十倍但reetrantlock性能能维持常态。 reentrantLock可重入性 内部自定义了同步器Sync既实现了AQS又实现了AOS—提供了一种互斥锁持有的方式加锁通过cas算法将线程对象放到一个双向链表中每次获取锁的时候看当前维护的那个线程id和当前请求的线程id是否一样一样就可重入了 synchronized保证原子性和可见性 volatile保证可见性 ThreadLocal和synchronized 都解决多线程并发访问 synchronized用于实现同步机制利用锁的机制使变量或代码块在某一时刻只能被一个线程访问 -----时间换空间 ThreadLocal为每个线程都提供变量的副本每个线程在某一时间访问到的不是同一个对象----空间换时间 ThreadLocal java提供的一种保护线程私有信息的机制其在整个线程生命周期内有效。方便地再一个线程关联的不同业务模块之间传递信息例如事务idcookie等上下文相关信息。 为每个线程维护变量的副本Map共享数据的可见范围为同一个线程之内。 使用注意remove 基于ThreadLocalMap实现key是个弱引用。废弃的回收依赖于显式的触发否则就要等待线程结束回收相应的ThreadLocalMap—OOM的来源。 建议应用要自己负责remove并且不要和线程池配合以为worker线程往往是不会退出的。 JUC并发工具java.util.concurrent及其子包 CountDownLatchCyclicBarrierSemaphore等可以实现更丰富的多线程操作的同步结构。 ConcurrentHashMap有序的ConcurrentSkipListMap或者通过类似快照机制实现线程安全的动态数组CopyOnWriteArrayList等各种线程安全的容器 ArrayBlockingQueue、SynchorousQueue或针对特定场景的PriorityBlockingQueue等各种并发队列实现 Executor框架可以创建各种不同类型的线程池调度任务运行等。 ReadWriteLock 和 StrampedLock 实际场景中不需要大量竞争的写操作以并发读为主进一步优化并发操作的粒度java提供了读写锁 ReadWriteLock 代表一对锁读锁和写锁数据量较大并发读多并发写少的时候能凸出优势。有相对大的开销 StrampedLock提供类似读写锁的同时支持优化读模式逻辑先试着修改然后通过validate方法确认是否进入写模式如果没有进入就成功避免了开销如果进入则尝试获取读锁。 public class StampedSample {private final StampedLock s1 new StampedLock();void mutate(){long stamp s1.writeLock();try{write();}finally {s1.unlockWrite(stamp);}}Data access(){long stamp s1.tryOptimisticRead();Data data read();if (!s1.validate(stamp)){stamp s1.readLock();try {data read();}finally {s1.unlockRead(stamp);}}return data;} }让线程彼此同步同步器 同步器CountDownLatchCyclicBarrierSemaphore实现多个线程之间协作的功能 CountDownLatch 倒计数允许一个或多个线程等待某些操作完成。 场景 跑步比赛等所有运动员(线程)到终点达成目标才去算排名和颁奖模拟并发启动100个线程同时访问某个地址同时并发不是一个一个执行 使用 CountDownLatch 构造方法指明计数数量被等待线程调用CountDownLatch 将计数器减1等待线程使用await进行线程等待。 CyclicBarrier 循环栅栏实现让一组线程等待至某个状态之后再全部执行而且当所有等待线程被释放后CyclicBarrier可以被重复使用 场景用来等待并发线程结束 主要方法await每被调用一次计数便会减少1并阻塞住当前线程。当计数减至0时阻塞解除所有在此CyclicBarrier上面阻塞的线程开始运行。之后如果再次调用await计数变成N-1新一轮重新开始CyclicBarrier.await带有返回值用来表示当前线程是第几个到达这个Barrier的线程。 Semaphorejava版本的信号量实现用于控制同时访问的线程个数来达到限制通用资源访问的目的原理是通过acquire获取一个许可如果没有就等待而release释放一个许可。如果值初始化为1那么一个线程就可以通过acquire进入互斥状态本质上和互斥锁是相似的区别互斥锁是持有者的而对于Semaphore这种计数器结构虽然有类似的功能但其实不存在真正意义上的持有者除非进行扩展包装。 CyclicBarrier和CountDownLatch 对比 行为有一定相似度区别 CountDownLatch 不可以重置无法重用CyclicBarrier可以重用 CountDownLatch 基本组合CountDown/await调用await的线程阻塞等待countDown足够的次数 CyclicBarrier基本组合CyclicBarrier/await当所有都调用了await 才继续进行任务并自动进行重置。 CountDownLatch 目的让一个线程等待其他n个线程达到某个条件后自己再去做某个事情 CyclicBarrier目的让N多线程互相等待直到所有的都达到某个状态然后这N个线程再继续执行各自后续。 java线程池的实现 线程被抽象为一个静态内部类worker基于AQS实现存放在线程池HashSet成员变量中 成员变量workQueueBlockingQueue需要执行的任务存放在成员变量中。 思想从workQueue中不断取出需要执行的任务放在workers中进行处理. 线程池核心构造参数 corePoolSize:核心线程数 maximumPoolSize:线程池允许的最大线程数 keepAliveTime超过核心线程数时闲置线程的存活时间 workQueue任务执行前保存任务的队列保存由execute方法提交的额Runnable任务 线程池中线程如何创建是一开始就随线程池的启动创建好的么 不是线程池默认初始化后不启动worker等有请求时才启动调用execute添加一个任务时线程池做如下的判断 正在运行的线程数量小于corePoolSize马上创建线程运行这个任务正在运行的线程数量大于等于corePoolSize将这个任务放入队列如果队列满了正在运行的线程数量小于maximumPoolSize还是要创建非核心线程立刻运行这个任务如果队列满了正在运行的线程数量大于或等于maximumPoolSize线程池会抛出异常RejectExecutionException 一个线程完成任务会从队列中取下一个任务来执行一个线程没有任务执行超过一定的时间keepAliveTime时线程池会判断如果当前运行的线程数大于corePoolSize线程会被停掉所有线程池的所有任务完成后最终会收缩到corePoolSize的大小。 默认线程池 SingleThreadExecutor 线程池只有一个核心线程在工作相当于单线程串行执行所有任务如果唯一线程因为异常结束会有一个新的线程来替代它此线程池保证所有任务的执行顺序按照任务的提交顺序执行 corePoolSize1maximumPoolSize1keepAliveTime0LworkQueuenew LinkedBlockingQueue器缓冲队列是无界的。 FixedThreadPool线程池固定大小的线程池只有核心线程每次提交一个任务就创建一个线程直到线程达到线程池的最大大小。多数针对一些很稳定很固定的正规并发线程多用于服务器 CachedThreadPool线程池无界线程池如果线程池的大小超过了处理任务所需要的线程那么就会回收部分空闲线程当任务数增加时此线程池又可以智能的添加新任务来处理任务。线程池大小完全依赖于操作系统能够创建的最大线程大小SynchronousQueue是一个缓冲区为1的阻塞队列缓存性通常用于执行一些生存期很短的异步型任务在一些面向连接的daemon型SERVER中用得不多但对于生存期短的异步任务是首选。 ScheduledThreadPool核心线程池固定大小无限的线程池支持定时周期性的执行任务的需求创建一个周期性执行任务的线程池如果闲置非核心线程会在DEFAULT_KEEPALIVEMILLIS时间内回收。 在java线程池中提交线程 executeExecutorService.execute方法接收一个Runnable示例 用来执行任务submitExecutorService.submit方法返回的是Future对象可以用isDone来查询Future是否已经完成当任务完成时具有一个结果可以调用get来获取结果。也可以直接get此时get将阻塞直至结果准备就绪。
http://www.dnsts.com.cn/news/182755.html

相关文章:

  • 优秀的手机网站案例网站文章后台写完前台不显示
  • 最新招聘信息seo技术
  • 网站在线制作平台wordpress文章中图片
  • 一流专业建设网站大兴西红门网站建设
  • 今科云平台网站建设技术开发自助建站免费申请个人网页
  • 建立手机网站万户网络待遇怎么样
  • 折800网站模板乐安网站建设
  • 广饶县城乡规划建设局网站网站安全建设目的是什么
  • 手机开发网站教程石家庄做网站的
  • 爱做网站外国宣讲家网站李慎明两学一做
  • 邓亚萍20亿做网站wordpress实名插件
  • 韩都衣舍网站建设策划书wordpress新闻类主题
  • drupal 网站开发安徽金开建设集团网站
  • 网站做链接算侵权吗湖南省建设信息网
  • 网站建设标准合同书直播网站建设1个节点多少钱
  • 医疗网站建设多少钱无锡做网站优化多少钱
  • 家装公司建设网站网站怎么接入百度地图
  • 百度网站数据统计怎么做网站开发流程图工具
  • 怎么免费做个人网站本科软件开发专业
  • 怎么看出网站是dede做的用照片做模板下载网站
  • 商城网站后续费用竞价广告是什么意思
  • 做内网网站怎么增加网站的反链
  • 网站的设计要素宁波北仑网站建设
  • 东莞网站开发网站建设制作费用网站建设公司东莞
  • 网站建设更新维护工作总结网络推广方案的内容
  • html5公司网站源码云南推广公司
  • 高乐雅官方网站 哪个公司做的国内最新新闻十篇
  • 山东电力建设网站上海怎么建设网站
  • 有关网站开发的文献或论文网站备案icp过期
  • 动漫网站开发免费网站封装app