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

成品网站商业网络

成品网站,商业网络,高端瓶装水品牌,九江做网站大概多少钱目录 1、线程生命周期 2、线程创建方式 3、Callable 与 Future 4、如何停止一个正在运行的线程 5、notify() 和 notifyAll() 的区别 6、sleep() 和 wait() 的区别 7、start() 和 run() 的区别 8、interrupted 和 isInterruptedd 的区别 9、CyclicBarrier 和 Count…目录 1、线程生命周期 2、线程创建方式 3、Callable 与 Future  4、如何停止一个正在运行的线程  5、notify() 和 notifyAll() 的区别 6、sleep() 和 wait() 的区别  7、start() 和 run() 的区别  8、interrupted 和 isInterruptedd 的区别 9、CyclicBarrier 和 CountDownLatch 的区别  10、synchronized 和 ReentrantLock 的区别 11、为什么 wait、notify、notifyAll 这些方法不在thread类 12、为什么 wait 和 notify 方法要在同步块中调用  13、Thread类中的yield方法有什么作用  14、volatile 15、volatile 可以保证有序性吗?  16、synchronized 17、Semaphore 18、SynchronizedMap 与 ConcurrentHashMap 的区别  19、线程之间是如何通信的 20、锁的优化机制  21、CAS 的原理  22、CAS 有什么缺点吗  23、什么是AQS  24、乐观锁与悲观锁 25、产生死锁的四个必要条件   26、如何避免死锁 27、说说ThreadLocal原理 28、有三个线程T1,T2,T3,如何保证顺序执行  29、说说线程池  30、什么是阻塞队列  31、线程池核心线程数怎么设置呢   32、常用的线程池有哪些 33、线程池中 submit() 和 execute() 的区别  34、什么是多线程中的上下文切换  35、什么是Daemon线程  36、什么是线程安全  37、Vector是一个线程安全类吗 38、线程安全需要保证几个基本特征   39、多线程有什么用  1、线程生命周期 2、线程创建方式 继承Thread类 public class Thread01 extends Thread {Overridepublic void run() {System.out.println(当前线程Thread.currentThread().getId());}public static void main(String[] args) {Thread01 thread new Thread01();thread.start();}} 实现Runnable接口 public class Runnable01 implements Runnable {Overridepublic void run() {System.out.println(当前线程Thread.currentThread().getId());}public static void main(String[] args) {Runnable01 runnable new Runnable01();new Thread(runnable).start();}} 实现Callable接口 JDK1.5 public class Callable01 implements CallableInteger {Overridepublic Integer call() throws Exception {System.out.println(当前线程Thread.currentThread().getId());int i 10/2;return i;}public static void main(String[] args) throws Exception {Callable01 callable new Callable01();FutureTaskInteger futureTask new FutureTask(callable);Thread thread new Thread(futureTask);thread.start();System.out.println(当前线程执行结果futureTask.get());}} 线程池方式创建 ExecutorService executor Executors.newFixedThreadPool(10); 总结  采用实现Runnable、Callable接口的方式创建线程的优缺点  优点线程类只是实现了Runnable或者Callable接口还可以继承其他类。这种方式下多个线程 可以共享一个target对象所以非常适合多个相同线程来处理同一份资源的情况从而可以将 CPU、代码和数据分开形成清晰的模型较好的体现了面向对象的思想。缺点编程稍微复杂一些如果需要访问当前线程则必须使用 Thread.currentThread() 方法 。  采用继承Thread类的方式创建线程的优缺点  优点编写简单如果需要访问当前线程则无需使用 Thread.currentThread() 方法直接使用 this即可获取当前线程缺点因为线程类已经继承了Thread类Java语言是单继承的所以就不能再继承其他父类了。  3、Callable 与 Future  Callable接口类似于Runnable从名字就可以看出来了但是Runnable不会返回结果并且无法抛出返回结果的异常而Callable功能更强大一些被线程执行后可以返回值这个返回值可以被 Future拿到也就是说Future可以拿到异步执行任务的返回值。可以认为是带有回调的Runnable。 Future接口表示异步任务是还没有完成的任务给出的未来结果。所以说Callable用于产生结果Future 用于获取结果。  4、如何停止一个正在运行的线程  使用退出标志使线程正常退出也就是当run方法完成后线程终止。 使用stop方法强行终止但是不推荐这个方法因为stop和suspend及resume一样都是过期作 废的方法。 使用interrupt方法中断线程。 class MyThread extends Thread {volatile boolean stop false;public void run() {while (!stop) {System.out.println(getName() is running);try {sleep(1000);} catch (InterruptedException e) {System.out.println(week up from blcok...);stop true; // 在异常处理代码中修改共享变量的状态}}System.out.println(getName() is exiting...);} } class InterruptThreadDemo3 {public static void main(String[] args) throws InterruptedException {MyThread m1 new MyThread();System.out.println(Starting thread...);m1.start();Thread.sleep(3000);System.out.println(Interrupt thread...: m1.getName());m1.stop true; // 设置共享变量为truem1.interrupt(); // 阻塞时退出阻塞状态Thread.sleep(3000); // 主线程休眠3秒以便观察线程m1的中断情况System.out.println(Stopping application...);} } 5、notify() 和 notifyAll() 的区别 notify 可能会导致死锁而 notifyAll 则不会。 任何时候只有一个线程可以获得锁也就是说只有一个线程可以运行 synchronized 中的代码。 使用 notifyall 可以唤醒 所有处于wait 状态的线程使其重新进入锁的争夺队列中而 notify 只能唤醒一个。 wait() 应配合 while 循环使用不应使用 if务必在 wait() 调用前后都检查条件如果不满足必须调 用 notify() 唤醒另外的线程来处理自己继续 wait() 直至条件满足再往下执行。 notify() 是对 notifyAll() 的一个优化但它有很精确的应用场景并且要求正确使用。不然可能导致 死锁。正确的场景应该是 WaitSet 中等待的是相同的条件唤醒任一个都能正确处理接下来的事项如果唤醒的线程无法正确处理务必确保继续 notify() 下一个线程并且自身需要重新回到 WaitSet 中。 6、sleep() 和 wait() 的区别  对于 sleep() 方法我们首先要知道该方法是属于 Thread 类中的。而 wait() 方法则是属于Object 类中的。 sleep() 方法导致了程序暂停执行指定的时间让出 cpu 该其他线程但是他的监控状态依然保持者当指定的时间到了又会自动恢复运行状态。在调用 sleep() 方法的过程中线程不会释放对象锁。 当调用 wait() 方法的时候线程会放弃对象锁进入等待此对象的等待锁定池只有针对此对象调用 notify() 方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。  7、start() 和 run() 的区别  start() 方法被用来启动新创建的线程而且 start() 内部调用了 run() 方法这和直接调用run()方法的效果不一样。当你调用 run() 方法的时候只会是在原来的线程中调用没有新的线程启动start() 方法才会启动新线程。  8、interrupted 和 isInterruptedd 的区别 interrupted() 和 isInterrupted() 的主要区别是前者会将中断状态清除而后者不会。 Java多线程的中断机制是用内部标识来实现的调用 Thread.interrupt() 来中断一个线程就会设置中断标识为 true。当中断线程调用静态方法 Thread.interrupted() 来检查中断状态时中断状态会被清零。而非静态方法 isInterrupted() 用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出 InterruptedException 异常的方法都会将中断状态清零。 9、CyclicBarrier 和 CountDownLatch 的区别  两个看上去有点像的类都在java.util.concurrent下都可以用来表示代码运行到某个点上二者的区别在于 CyclicBarrier 的某个线程运行到某个点上之后该线程即停止运行直到所有的线程都到达了这个点所有线程才重新运行CountDownLatch 则不是某线程运行到某个点上之后只是给某个数值 -1 而已该线程继续运行。CyclicBarrier 只能唤起一个任务CountDownLatch 可以唤起多个任务。CyclicBarrier 可重用CountDownLatch 不可重用计数值为 0 该 CountDownLatch 就不可再用了。 10、synchronized 和 ReentrantLock 的区别 相似点  这两种同步方式有很多相似之处它们都是加锁方式同步而且都是阻塞式的同步也就是说当如 果一个线程获得了对象锁进入了同步块其他访问该同步块的线程都必须阻塞在同步块外面等 待而进行线程阻塞和唤醒的代价是比较高的。 区别  这两种方式最大区别就是对于Synchronized来说它是java语言的关键字是原生语法层面的互 斥需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁需要lock()和 unlock()方法配合try/finally语句块来完成。 Synchronized进过编译会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时首先要尝试获取对象锁。如果这个对象没被锁定或者当前线程已经拥有了那个对象锁把锁的计算器加1相应的在执行monitorexit指令时会将锁计算器就减1当计算器为0时锁就被释放了。如果获取对象锁失败那当前线程就要阻塞直到对象锁被另一个线程释放为止。 由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁相比Synchronized ReentrantLock类提供了一些高级功能主要有以下3项 等待可中断持有锁的线程长期不释放的时候正在等待的线程可以选择放弃等待这相当于Synchronized来说可以避免出现死锁的情况。公平锁多个线程等待同一个锁时必须按照申请锁的时间顺序获得锁Synchronized锁非公平锁ReentrantLock默认的构造函数是创建的非公平锁可以通过参数true设为公平锁但公平锁表现的性能不是很好。锁绑定多个条件一个ReentrantLock对象可以同时绑定对个对象。 11、为什么 wait、notify、notifyAll 这些方法不在thread类 明显的原因是 Java 提供的锁是对象级的而不是线程级的每个对象都有锁通过线程获得。如果线 程需要等待某些锁那么调用对象中的 wait() 方法就有意义了。如果 wait() 方法定义在 Thread 类中线 程正在等待的是哪个锁就不明显了。简单的说由于waitnotify和notifyAll都是锁级别的操作所 以把他们定义在Object类中因为锁属于对象。  12、为什么 wait 和 notify 方法要在同步块中调用  只有在调用线程拥有某个对象的独占锁时才能够调用该对象的wait(),notify()和notifyAll()方法。如果你不这么做你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。  wait()方法强制当前线程释放对象锁。这意味着在调用某对象的wait()方法之前当前线程必须已经 获得该对象的锁。因此线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方法。 在调用对象的notify()和notifyAll()方法之前调用线程必须已经得到该对象的锁。因此必须在某 个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。 调用wait()方法的原因通常是调用线程希望某个特殊的状态(或变量)被设置之后再继续执行。调用 notify()或notifyAll()方法的原因通常是调用线程希望告诉其他等待中的线程:特殊状态已经被设 置。这个状态作为线程间通信的通道它必须是一个可变的共享状态(或变量)。  13、Thread类中的yield方法有什么作用  yield 方法可以暂停当前正在执行的线程对象让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃 CPU 占用而不能保证使其它线程一定能占用 CPU执行 yield() 的线程有可能在进入到暂停状态后马上又被执行。  14、volatile 一个共享变量(类的成员变量、类的静态成员变量)被 volatile 修饰之后那么就具备了两层语义  保证了不同线程对这个变量进行操作时的可见性即一个线程修改了某个变量的值这新值对其他线程来说是立即可见的volatile关键字会强制将修改的值立即写入主存。禁止进行指令重排序。  volatile 不是原子性操作使用volatile 一般用于 状态标记量 和 单例模式的双检锁。 15、volatile 可以保证有序性吗?  什么叫保证部分有序性 当程序执行到volatile变量的读操作或者写操作时在其前面的操作的更改肯定全部已经进行且结果已经对后面的操作可见在其后面的操作肯定还没有进行。 x 2; //语句1 y 0; //语句2 flag true; //语句3 x 4; //语句4 y -1; //语句5 由于flag变量为volatile变量那么在进行指令重排序的过程的时候不会将语句3放到语句1、语句 2前面也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5 的顺序是不作任何保证的。 16、synchronized synchronized 关键字解决的是多个线程之间访问资源的同步性synchronized 关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。 另外在 Java 早期版本中synchronized属于重量级锁效率低下因为监视器锁monitor是依赖于底层的操作系统的 Mutex Lock 来实现的Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一 个线程都需要操作系统帮忙完成而操作系统实现线程之间的切换时需要从用户态转换到内核 态这个状态之间的转换需要相对比较长的时间时间成本相对较高这也是为什么早期的synchronized 效率低的原因。庆幸的是在 Java 6 之后 Java 官方对从 JVM 层面对 synchronized 较大优化所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。 修饰实例方法作用于当前对象实例加锁进入同步代码前要获得当前对象实例的锁。  修饰静态方法也就是给当前类加锁会作用于类的所有对象实例因为静态成员不属于任何一个实例对象是类成员 static 表明这是该类的一个静态资源不管new了多少个对象只有一份。所以如果一个线程A调用一个实例对象的非静态 synchronized 方法而线程B需要调用这个实例对象所属类的静态 synchronized 方法是允许的不会发生互斥现象因为访问静态 synchronized 方法占用的锁是当前类的锁而访问非静态 synchronized 方法占用的锁是当前实例对象锁。 修饰代码块指定加锁对象对给定对象加锁进入同步代码库前要获得给定对象的锁。 总结synchronized 关键字加到 static 静态方法和 synchronized(class) 代码块上都是是给 Class 类上锁。synchronized 关键字加到实例方法上是给对象实例上锁。尽量不要使 synchronized(String a) 因为JVM中字符串常量池具有缓存功能 17、Semaphore Semaphore就是一个信号量它的作用是限制某段代码块的并发数。Semaphore有一个构造函数可以传入一个int型整数n表示某段代码最多只有n个线程可以访问如果超出了n那么请等待等到某个线程执行完毕这段代码块下一个线程再进入。由此可以看出如果Semaphore构造函数中传入的int型整数n1相当于变成了一个synchronized了。  18、SynchronizedMap 与 ConcurrentHashMap 的区别  SynchronizedMap() 和 Hashtable 一样实现上在调用 map 所有方法时都对整个 map 进行同步。而ConcurrentHashMap的实现却更加精细它对 map 中的所有桶加了锁。所以只要有一个线程访问 map其他线程就无法进入 map而如果一个线程在访问 ConcurrentHashMap 某个桶时其他线程仍然可以对 map 执行某些操作。 所以ConcurrentHashMap 在性能以及安全性方面明显比 Collections.synchronizedMap() 更加 有优势。同时同步操作精确控制到桶这样即使在遍历 map 时如果其他线程试图对 map 进行数据修改也不会抛出 ConcurrentModificationException。  19、线程之间是如何通信的 共享内存 在共享内存的并发模型里线程之间共享程序的公共状态线程之间通过写-读内存中的公共状态来隐式进行通信。典型的共享内存通信方式就是通过共享对象进行通信。 如线程 A 与 线程 B 之间如果要通信的话那么就必须经历下面两个步骤 线程 A 把本地内存 A 更新过得共享变量刷新到主内存中去。线程 B 到主内存中去读取线程 A 之前更新过的共享变量。 消息传递  在消息传递的并发模型里线程之间没有公共状态线程之间必须通过明确的发送消息来显式进行 通信。在 Java 中典型的消息传递方式就是 wait() 和 notify() 或者 BlockingQueue 。  20、锁的优化机制  从JDK1.6版本之后synchronized本身也在不断优化锁的机制有些情况下他并不会是一个很重量级的锁了。优化机制包括自适应锁、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁。锁的状态从低到高依次为无锁-偏向锁-轻量级锁-重量级锁升级的过程就是从低到高降级在一定条件也是有可能发生的。  自旋锁由于大部分时候锁被占用的时间很短共享变量的锁定时间也很短所有没有必要挂起 线程用户态和内核态的来回上下文切换严重影响性能。自旋的概念就是让线程执行一个忙循环 可以理解为就是啥也不干防止从用户态转入内核态自旋锁可以通过设置-XX:UseSpining来开 启自旋的默认次数是10次可以使用-XX:PreBlockSpin设置。 自适应锁自适应锁就是自适应的自旋锁自旋的时间不是固定时间而是由前一次在同一个锁上 的自旋时间和锁的持有者状态来决定。 锁消除锁消除指的是JVM检测到一些同步的代码块完全不存在数据竞争的场景也就是不需要 加锁就会进行锁消除。 锁粗化锁粗化指的是有很多操作都是对同一个对象进行加锁就会把锁的同步范围扩展到整个操 作序列之外。 偏向锁当线程访问同步块获取锁时会在对象头和栈帧中的锁记录里存储偏向锁的线程ID之后 这个线程再次进入同步块时都不需要CAS来加锁和解锁了偏向锁会永远偏向第一个获得锁的线 程如果后续没有其他线程获得过这个锁持有锁的线程就永远不需要进行同步反之当有其他 线程竞争偏向锁时持有偏向锁的线程就会释放偏向锁。可以用过设置-XX:UseBiasedLocking开 启偏向锁。 轻量级锁JVM的对象的对象头中包含有一些锁的标志位代码进入同步块的时候JVM将会使用 CAS方式来尝试获取锁如果更新成功则会把对象头中的状态位标记为轻量级锁如果更新失败 当前线程就尝试自旋来获得锁。 21、CAS 的原理  CAS 叫做 CompareAndSwap比较并交换主要是通过处理器的指令来保证操作的原子性它包含三个操作数  变量内存地址V表示旧的预期值A表示准备设置的新值B表示  当执行CAS指令时只有当V等于A时才会用B去更新V的值否则就不会执行更新操作。  22、CAS 有什么缺点吗  ABA问题ABA的问题指的是在CAS更新的过程中当读取到的值是A然后准备赋值的时候仍然是A但是实际上有可能A的值被改成了B然后又被改回了A这个CAS更新的漏洞就叫做ABA。只是ABA的问题大部分场景下都不影响并发的最终效果。 Java中有AtomicStampedReference来解决这个问题他加入了预期标志和更新后标志两个字段 更新时不光检查值还要检查当前的标志是否等于预期标志全部相等的话才会更新。  循环时间长开销大自旋CAS的方式如果长时间不成功会给CPU带来很大的开销。  只能保证一个共享变量的原子操作只对一个共享变量操作可以保证原子性但是多个则不行多 个可以通过AtomicReference来处理或者使用锁synchronized实现。  23、什么是AQS  AQS 全称为 AbstractQueuedSychronizer翻译过来应该是抽象队列同步器。 如果说 java.util.concurrent 的基础是 CAS 的话那么 AQS 就是整个 Java 并发包的核心了 ReentrantLock、CountDownLatch、Semaphore等等都用到了它。AQS实际上以双向队列的形式 连接所有的Entry比方说ReentrantLock所有等待的线程都被放在一个Entry中并连成双向队 列前面一个线程使用ReentrantLock好了则双向队列实际上的第一个Entry开始运行。 AQS 定义了对双向队列所有的操作而只开放了 tryLock 和 tryRelease 方法给开发者使用开发者可以根据自己的实现重写 tryLock 和 tryRelease 方法以实现自己的并发功能。  24、乐观锁与悲观锁 悲观锁总是假设最坏的情况每次去拿数据的时候都认为别人会修改所以每次在拿数据的时候 都会上锁这样别人想拿这个数据就会阻塞直到它拿到锁。 传统的关系型数据库里边就用到了很多这种锁机制比如行锁表锁等读锁写锁等都是在做 操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。 乐观锁顾名思义就是很乐观每次去拿数据的时候都认为别人不会修改所以不会上锁但是 在更新的时候会判断一下在此期间别人有没有去更新这个数据可以使用版本号等机制。  乐观锁适用于多读的应用类型这样可以提高吞吐量像数据库提供的类似于write_condition机制其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。 乐观锁的实现方式 使用版本标识来确定读到的数据与提交时的数据是否一致。提交后修改版本标识不一致时可以采取丢弃和再次尝试的策略。java中的Compare and Swap即CAS 当多个线程尝试使用CAS同时更新同一个变量时只有其中一个线程能更新变量的值而其它线程都失败失败的线程并不会被挂起而是被告知这次竞争中失败并可以再次尝试。 CAS 操作中包含三个操作数 —— 需要读写的内存位置V、进行比较的预期原值A和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。 25、产生死锁的四个必要条件   互斥条件一个资源每次只能被一个线程使用。请求与保持条件一个线程因请求资源而阻塞时对已获得的资源保持不放。不剥夺条件进程已经获得的资源在未使用完之前不能强行剥夺。循环等待条件若干线程之间形成一种头尾相接的循环等待资源关系。 26、如何避免死锁 指定获取锁的顺序 比如某个线程只有获得A锁和B锁才能对某资源进行操作规定只有获得A锁的线程才有资格获取B锁。  27、说说ThreadLocal原理 ThreadLocal可以理解为线程本地变量他会在每个线程都创建一个副本那么在线程之间访问内部副本变量就行了做到了线程之间互相隔离相比于synchronized的做法是用空间来换时间。  ThreadLocal有一个静态内部类ThreadLocalMapThreadLocalMap又包含了一个Entry数组 Entry本身是一个弱引用他的key是指向ThreadLocal的弱引用Entry具备了保存key value键值对 的能力。弱引用的目的是为了防止内存泄露如果是强引用那么ThreadLocal对象除非线程结束否则始终无法被回收弱引用则会在下一次GC的时候被回收。 但是这样还是会存在内存泄露的问题假如key和ThreadLocal对象被回收之后entry中就存在key 为null但是value有值的entry对象但是永远没办法被访问到同样除非线程结束运行。  但是只要ThreadLocal使用恰当在使用完之后调用remove方法删除Entry对象实际上是不会出 现这个问题的。  28、有三个线程T1,T2,T3,如何保证顺序执行  public class JoinTest {public static void main(String[] args) {final Thread t1 new Thread(new Runnable() {Overridepublic void run() {System.out.println(t1);}});final Thread t2 new Thread(new Runnable() {Overridepublic void run() {try {// 引用t1线程等待t1线程执行完t1.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(t2);}});Thread t3 new Thread(new Runnable() {Overridepublic void run() {try {// 引用t2线程等待t2线程执行完t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(t3);}});// 这里三个线程的启动顺序可以任意大家可以试下t3.start();t2.start();t1.start();} } 29、说说线程池  Configuration public class ThreadConfig {Beanpublic ThreadPoolExecutor executor(ThreadPoolProperties properties) {return new ThreadPoolExecutor(properties.getCoreSize(),properties.getMaxSize(),properties.getKeepAliveTime(),TimeUnit.SECONDS,new LinkedBlockingQueue(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}} ThreadPoolExecutor 参数 int corePoolSize核心线程数量线程池创建好以后就存在int maximumPoolSize最大线程数量控制资源long keepAliveTime存活时间如果当前线程数量大于corePoolSize线程空闲时间大于keepAliveTime释放空闲的线程maximumPoolSize-corePoolSizeTimeUnit unit时间单位BlockingQueueRunnable workQueue阻塞队列如果任务很多就会将目前多的任务放在队列中只要线程空闲就会去队列中取出新的任务继续执行  LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列不指定就是Integer最大值。 ArrayBlockingQueue 一个由数组结构组成的有界阻塞队列。 PriorityBlockingQueue 一个支持优先级排序的无界阻塞队列。 DelayQueue一个使用优先级队列实现的无界阻塞队列。 SynchronousQueue一个不存储元素的阻塞队列。 LinkedTransferQueue一个由链表结构组成的无界阻塞队列。 LinkedBlockingDeque一个由链表结构组成的双向阻塞队列。 ThreadFactory threadFactory线程创建工厂RejectedExecutionHandler handler如果队列满了按照我们指定的拒绝策略拒绝执行任务  new AbortPolicy()丢弃抛异常默认策略。 new CallerRunsPolicy()直接调用run方法。 new DiscardOldestPolicy()丢弃队列队头任务并执行当前任务。 new DiscardPolicy()丢弃当前任务也不抛出异常。    工作流程 线程池创建准备好corePoolSize数量的核心线程准备接受任务。corePoolSize满了就将再进来的任务放入阻塞队列中。workQueue满了就直接开启新线程执行最大只能开到maximumPoolSize指定的数量。maximumPoolSize满了使用handler拒绝任务。任务都执行完成空闲很多线程在指定的keepAliveTime后释放maximumPoolSize-corePoolSize这些线程。 示例 一个 corePoolSize7maximumPoolSize20workQueue50的线程池100个并发进来怎么处理 7个任务立即执行50个任务进入队列再开13个线程进行执行剩下30个任务使用拒绝策略。  总结 降低资源的消耗通过重复利用已创建好的线程降低线程的创建和销毁带来的损耗。提高响应速度因为线程池中的线程没有超过线程池的最大上限时有的线程处于等待分配任务的状态当任务来时无需创建新的线程就能执行。提高线程的可管理性线程池会根据当前系统特点对池内的线程进行优化处理减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源还降低系统的稳定性使用线程池进行统一分配。 30、什么是阻塞队列  阻塞队列BlockingQueue是一个支持两个附加操作的队列。  这两个附加的操作是在队列为空时获取元素的线程会等待队列变为非空。当队列满时存储元 素的线程会等待队列可用。 JDK7提供了7个阻塞队列。分别是 ArrayBlockingQueue 一个由数组结构组成的有界阻塞队列。LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列。PriorityBlockingQueue 一个支持优先级排序的无界阻塞队列。DelayQueue一个使用优先级队列实现的无界阻塞队列。SynchronousQueue一个不存储元素的阻塞队列。LinkedTransferQueue一个由链表结构组成的无界阻塞队列。LinkedBlockingDeque一个由链表结构组成的双向阻塞队列。 阻塞队列常用于生产者和消费者的场景生产者是往队列里添加元素的线程消费者是从队列里拿 元素的线程。阻塞队列就是生产者存放元素的容器而消费者也只从容器里拿元素。 Java 5之前实现同步存取时可以使用普通的一个集合然后在使用线程的协作和线程同步可以实 现生产者消费者模式主要的技术就是用好wait ,notify,notifyAll,sychronized这些关键字。而 在java 5之后可以使用阻塞队列来实现此方式大大简少了代码量使得多线程编程更加容易 安全方面也有保障。 BlockingQueue接口是Queue的子接口它的主要用途并不是作为容器而是作为线程同步的的工 具因此他具有一个很明显的特性当生产者线程试图向BlockingQueue放入元素时如果队列已 满则线程被阻塞当消费者线程试图从中取出一个元素时如果队列为空则该线程会被阻塞 正是因为它所具有这个特性所以在程序中多个线程交替向BlockingQueue中放入元素取出元 素它可以很好的控制线程之间的通信。 阻塞队列使用最经典的场景就是socket客户端数据的读取和解析读取数据的线程不断将数据放入 队列然后解析线程不断从队列取数据解析。 31、线程池核心线程数怎么设置呢   CPU密集型  这种任务消耗的主要是 CPU 资源可以将线程数设置为 NCPU 核心数1比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断或者其它原因导致的任务暂停而带来的影响。一旦任务暂停CPU 就会处于空闲状态而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。 IO密集型 这种任务应用起来系统会用大部分的时间来处理 I/O 交互而线程在处理 I/O 的时间段内不会占 用 CPU 来处理这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中我们可以多配置一些线程具体的计算方法是 核心线程数CPU核心数量*2。  32、常用的线程池有哪些 newSingleThreadExecutor创建一个单线程的线程池此线程池保证所有任务的执行顺序按照任务的提交顺序执行。newFixedThreadPool创建固定大小的线程池每次提交一个任务就创建一个线程直到线程达到线程池的最大大小。newCachedThreadPool创建一个可缓存的线程池此线程池不会对线程池大小做限制线程池大小完全依赖于操作系统或者说JVM能够创建的最大线程大小。newScheduledThreadPool创建一个大小无限的线程池此线程池支持定时以及周期性执行任务的需求。newSingleThreadExecutor创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。  33、线程池中 submit() 和 execute() 的区别  两个方法都可以向线程池提交任务execute() 方法的返回类型是 void它定义在 Executor 接口中而 submit() 方法可以返回持有计算结果的 Future 对象它定义在 ExecutorService 接口中它扩展了 Executor 接口其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。    34、什么是多线程中的上下文切换  在上下文切换过程中CPU会停止处理当前运行的程序并保存当前程序运行的具体位置以便之后 继续运行。从这个角度来看上下文切换有点像我们同时阅读几本书在来回切换书本的同时我们 需要记住每本书当前读到的页码。 在程序中上下文切换过程中的“页码”信息是保存在进程控制块PCB中的。PCB还经常被称 作“切换桢”switchframe。“页码”信息会一直保存到CPU的内存中直到他们被再次使用。 上下文切换是存储和恢复CPU状态的过程它使得线程执行能够从中断点恢复执行。上下文切换是 多任务操作系统和多线程环境的基本特征。  35、什么是Daemon线程  所谓后台(daemon)线程也叫守护线程是指在程序运行的时候在后台提供一种通用服务的线程并且这个线程并不属于程序中不可或缺的部分。因此当所有的非后台线程结束时程序也就终止了同时会杀死进程中的所有后台线程。反过来说只要有任何非后台线程还在运行程序就不会终止。必须在线程启动之前调用setDaemon()方法才能把它设置为后台线程。 注意后台线程在不执行 finally 子句的情况下就会终止其run()方法。 比如JVM的垃圾回收线程就是Daemon线程Finalizer也是守护线程。   36、什么是线程安全  如果你的代码所在的进程中有多个线程在同时运行而这些线程可能会同时运行这段代码。如果每 次运行结果和单线程运行的结果是一样的而且其他的变量的值也和预期的是一样的就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失 误。很显然你可以将集合类分成两组线程安全和非线程安全的。  37、Vector是一个线程安全类吗 Vector 是用同步方法来实现线程安全的, 而和它相似的 ArrayList 不是线程安全的。  38、线程安全需要保证几个基本特征   原子性简单说就是相关操作不会中途被其他线程干扰一般通过同步机制实现。可见性是一个线程修改了某个共享变量其状态能够立即被其他线程知晓通常被解释为将线程本地状态反映到主内存上volatile 就是负责保证可见性的。有序性是保证线程内串行语义避免指令重排等。  39、多线程有什么用  发挥多核CPU的优势 随着工业的进步现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的4核、8核甚至 16核的也都不少见如果是单线程的程序那么在双核CPU上就浪费了50%在4核CPU上就浪费 了75%。单核CPU上所谓的多线程那是假的多线程同一时间处理器只会处理一段逻辑只不过 线程之间切换得比较快看着像多个线程同时运行罢了。多核CPU上的多线程才是真正的多线 程它能让你的多段逻辑同时工作多线程可以真正发挥出多核CPU的优势来达到充分利用 CPU的目的。 防止阻塞  从程序运行效率的角度来看单核CPU不但不会发挥出多线程的优势反而会因为在单核CPU上运行多线程导致线程上下文的切换而降低程序整体的效率。但是单核CPU我们还是要应用多线程就是为了防止阻塞。试想如果单核CPU使用单线程那么只要这个线程阻塞了比方说远程读取某个数据吧对端迟迟未返回又没有设置超时时间那么你的整个程序在数据返回回来之前就停止运行了。多线程可以防止这个问题多条线程同时运行哪怕一条线程的代码执行读取数据阻塞也不会影响其它任务的执行。 便于建模 这是另外一个没有这么明显的优点了。假设有一个大的任务A单线程编程那么就要考虑很多 建立整个程序模型比较麻烦。但是如果把这个大的任务A分解成几个小任务任务B、任务C、任务 D分别建立程序模型并通过多线程分别运行这几个任务那就简单很多了。
http://www.tj-hxxt.cn/news/134222.html

相关文章:

  • 主流的自助建站网站网页制作怎么添加视频
  • 舟山公司网站制作网站建设价目表
  • 要实现对网站中的所有内容进行搜索代码应该怎么写网站建设技术清单
  • 网站太花哨外贸网站建站要多少钱
  • 土地流转网站建设报告平台网站建设公司哪家好
  • 坦克大战网站开发课程设计报告网站建设z亿玛酷1订制
  • 一个页面对网站如何建设wordpress可以做电影站
  • 云南省网站建设成都网站制作哪家专业
  • 内蒙古网站制作公司台州建设网站制作
  • 空间商网站腾讯网站建设公司
  • 珠海做公司网站如何做简易的网站
  • 河北省建设工程造价管理协会网站微门户网站建设
  • 公司网站网页制作建议海北网站建设
  • 如何进行网页设计和网站制作网站建设这个职业是什么意思
  • 怀化建设公司网站各大网址收录查询
  • 2017网站建设报价方案做网站的好公司有哪些
  • 宁波北仑做网站阿里云 发布网站 教程
  • 湖南网站开发哪家好深圳高端网站制作费用
  • 网站做程序外贸网站模板源码
  • 网站制作的主要流程网站建设 技术支持
  • 在百度做网站多少钱网站建设服务商城
  • 河南省建设教育协会网站php网站后台上传不了图片
  • 网站建设需要具备哪些做网站分pc端和移动端的吗
  • wordpress设置安全湛江百度seo公司
  • 上海青浦房地产网站建设简历设计网官网
  • 用插件做网站建站公司外贸
  • 现在做一个网站多少钱合肥寒假兼职工网站建设
  • 网站维护源码自适应58同城找工作招聘官网
  • 济南做网站公司哪家好网上虚拟银行注册网站
  • 界面官方网站专业格泰建站