中断线程:相当于一个线程给另一个线程一个通知或者请求让另一个线程中断,另一个线程不一定要接受请求进行中断,要看它对中断请求的处理方法。java中用boolean isInterrupted() 检测线程是否被终止。不改变中断的状态。在中断状态置位时调用sleep方法,不会休眠,相反会清除中断状态,并抛出IterruptedException。
sleep()(静态的方法):说白了就是在参数时间内该线程不参与cpu竞争。
1、当调用了sleep()或者wait(),然后boolean isInterrupted(),会抛出interruptedException异常。
2、当调用了sleep()或者wait(),调用void interrupt()后,会抛出InterruptedException,然后线程的中断标志位会由true重置为false(如果没有调用sleep()会置为true),因为线程为了处理异常已经重新处于就绪状态
3、调用static boolean interrupted()检测是否当前线程被中断,并会将当前线程的中断状态重置为false。
4、在中断状态置位时调用sleep方法,不会休眠,相反会清除中断状态,并抛出IterruptedException。
注意:当sleep抛出异常的同时会清除中断状态。
操作系统中,CPU竞争有很多种策略。Unix系统使用的是时间片算法,而Windows则属于抢占式的。 在时间片算法中,所有的进程排成一个队列。操作系统按照他们的顺序,给每个进程分配一段时间,即该进程 允许运行的时间。如果在 时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程 序所要做的就是维护一张就绪进程列表,,当进程用完它的时间片后,它被移到队列的末尾。 所谓抢占式操作系统,就是说如果一个进程得到了 CPU 时间,除非它自己放弃使用 CPU ,否则将完全霸占 CPU
线程守护:用t.setDaemon(boolean isDaemon) 参数true为守护线程,false为用户线程。守护线程为其他线程服务的,必须在线程启动前设置为守护线程。当只剩下守护线程时,JVM就退出。
未捕获异常处理器:run方法不能抛出任何被检测的异常,线程死亡,死亡前异常被传递到一个用于捕获异常的处理器,该处理器必须实行Thread.UncaughtExceptionHandler接口的类。1.用void setUncaughtExceptionHandler可以为任何一个线程安装一个处理器。2、用Thread的静态方法setDefaultUncaughtExceptionHandler为所以线程安装一个默认处理器。3.如果没有安装处理器,此时处理器就是ThreadGroup对象(其实现了Thread.UncaughtExceptionHandler接口),1)该线程组有父线程组则调用父线程组的uncaughtException方法。2)否则如果Thread.getDefaultExceptionHandler方法返回非空则调用此处理器。3)否则如果Throwablb是TreadDeath的一个实例,则什么都不做。4)否则线程的名字以及Throwable的栈踪迹被输出到System.err上。
线程锁:方法1)使用继承了Lock接口的ReentrantLock对象创建一个锁对象,在需要锁的代码段前使用该对象的Lock()方法,使得当前线程获得了该段代码的锁,其他线程无法进入,在当前线程不符条件的对方使用条件对象的await()方法,使得当前线程等待,交由条件对象管理。在代码段结束处用finally使用该锁对象的unLock()方法释放该段代码的锁,好让其他线程可以进入该段临界区代码。
方法2)把方法用Synchronized关键字修饰,那么该方法被设置了一个锁对象。在当前线程不符条件的对方使用静态方法wait()方法,使得当前线程等待,交由条件对象管理。此方法结束处使用线程静态方法notifyAll()唤醒其他阻塞的线程。
同步阻塞:可以使用Synchronized(obj)获得obj的锁。这种方法叫做客户端锁定,这种方法比较脆弱,不推荐使用。
volatile(不稳定的):Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值,使得并发访问它是安全的。
所测试与超时:lock方法不能被中断,这样如果出现死锁,lock方法就无法终止。可以使用tryLock(),也可以带时间参数。获得锁返回true,否则返回false,并且中途被中断会抛出InterruptedException异常,这样可以打破死锁,lockInterruptibly相当于无限的调用tryLock()方法。条件等待await()中断会抛出异常,awaitUninterruptibly()直到线程从等待集移除才解除阻塞,不会抛出异常。
读/写锁:ReentrantReadWriteLock对象,其readLock()与writeLock()返回Lock对象,分别是读锁和写锁。
弃用stop与suspend:stop()会终止所有未结束的线程,可能会导致对象处于不一致状态。suspend是挂起一个线程。但是如果该线程正获得锁,可能会导致死锁。
阻塞队列:工作者线程周期性的将中间结果存储在阻塞队列中,其他工作者线程移除中间结果并进一步修改。队列自动地平衡负载。java中常见的阻塞队列有LinkedBlockingQueue(可以有容量限制)ArrayBlockingQueue(容量限制),DelayQueue(超出了延迟时间的才能够移除队列),PriorityBlockingQueue(无容量上限,用堆实现)。所谓阻塞队列,是指在为空和满时,分别执行取操作和添加操作会发生阻塞。
线程安全的集合:把对象或值放入这些线程安全的集合中,可以使多线程并发的安全的访问这些放入的数据。
1)高效的映像、集合和队列。包括java类库中的ConcurrentHashMap<K,V>,ConcurrentSkipListMap<k,V>,ConcurrentSkipListSet<K,V>,ConcurrentLinkedQueue<E>,写数组拷贝:CopyOnWriteArrayList和CopyOnWriteArraySet(所以的修改数组线程对底层的数组进行复制)等。
2)Vector和Hashtable是线程安全的,但是被ArrayList和HashMap替代,这些不是线程安全的,但是可以用同步包装器变成线程安全的(Collections.synchronizedList(new ArrayList<E>())。
尽量使用java.until.concurrent包中的集合,不使用同步包装器中的,因为前者已经经常设计了的。
Callable和Future:Callable<V>相当于有返回值的Runnable,Future接口的方法中可以保持异步计算的结果(get()方法,是同步阻塞的)。用FutureTask包装器可以把Callable包装成Future和Runnable。
线程池:池中有一定的线程,有些线程可能在使用中,空闲的线程和使用完的线程不死亡,放在线程池中,当需要是不必再重新生成,这样可以节约时间。java中用Executor的多种静态方法可以生成线程池对象,然后把Runnable或者Callable对象传递进去就可以加入到线程池中了。
预定执行:ScheduledExecutorService接口具有为预定任务或重复执行任务而设计的方法。
控制任务组:可以便于同一组并发线程任务的管理。
同步器:1信号量(可以标志资源可用数) 2倒计时门栓(控制线程的运行,让计算器倒计时到0时继续运行)3障栅(当多个线程完成任务后一起再去完成下一步任务)4交换器(两个线程在同一缓冲区上工作时,比如一个线程向缓冲区填入数据。另一个线程读取数据。)5同步队列(与交换器不同的是它沿一个方向传递,从生产者到消费者)。