zoukankan      html  css  js  c++  java
  • Java多线程

    线程

    进程与线程的本质区别在于每个进程拥有自己的一整套变量,而线程则共享数据。

    Thread.sleep(long)就是用于暂停当前线程,没有必要Thread.currentThread().sleep(long)。 

    Runnable接口本身代表一个任务,然后需要启动一个Thread来执行这个任务。

    虽然可以直接构造一个Thread的子类,在run方法中实现任务功能,但不推荐这么做。应该从运行机制上减少需要并行运行的任务数量。如果有很多任务,要为每个任务创建一个独立的线程所付出的代价太大了。可以使用线程池来解决问题。 

    不要调用Thread类或Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启用新线程。应该调用Thread.start方法,这个方法将创建一个执行run方法的新线程。 

    每一个线程都有优先级,默认情况下,一个线程继承它的父线程的优先级。

    守护线程的唯一用途是为其他线程提供服务。当只剩下守护线程时,虚拟机就退出了。

    线程中断

    Thread.intertupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,设置线程的中断标示位。中断一个线程不过是引起它的注意,被中断的线程可以决定如何响应中断。

    每个线程都应该不时地检查中断状态位,以判断线程是否被中断。如果在每次工作迭代之后都调用sleep方法(或者其他的可中断方法),isInterrupted检测既没有必要也没有用处。因为Object.wait, Thread.sleep方法,会不断的轮询监听中断标志位,发现其设置为true后,会停止阻塞、重置中断标志位并抛出 InterruptedException异常。所以,不管是在线程是在被阻塞(调用sleep、wait、join)之前或者阻塞中调用interrupt,都会抛出InterruptedException异常,并清除线程的中断状态。程序可自行捕获异常并决定如何处理。

    interrupt对象方法用于向线程发送中断请求;

    interrupted静态方法测试当前线程的中断状态,并充值中断标示位;

    isInterrupted对象方法测试线程是否被中断,但并不改变中断状态。

    处于死锁状态的线程是无法被中断的。

    线程状态

    线程有6种状态:New(新创建)、Runnable(可运行)、Blocked(被阻塞)、Waiting(等待)、Timed Waiting(计时等待)、Terminated(被终止)。 

    当一个线程试图获取一个内部对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变成非阻塞状态。 

    当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态。被阻塞状态与等待状态是有很大不同的。

    线程同步

    Java中每一个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。并且该锁还有一个内部条件。静态方法也可以使用synchronized,如果调用这种方法,该方法获得相关的类对象的内部锁。 

    如果一个对象中有多个方法是synchronized,由于这些方法是共享的对象内部锁,所以即便不同线程访问同一对象中不同的synchronized方法,那也可能会阻塞等待。 

    ReentrantLock可重入锁是指线程可以重复获得已经持有的锁,锁保持一个持有计数来跟踪对lock方法的嵌套调用。被一个锁保护的代码可以调用另一个使用相同的锁的方法。 

    ReentrantLock()用来创建常规锁,ReentrantLock(boolean fair)用来创建公平锁。公平锁会倾向于根据线程等待时间来选择应该哪个线程获得锁,但并不保证一定这样。 

    wait、notifyAll以及notify方法是Object类的final方法。Condition方法必须命名为await、signalAll和signal以便他们不会与那些方法发生冲突。 

    条件对象用来管理那些已经获得了一个锁但是却不能做有用工作的线程。一个锁可以有一个或多个相关的条件对象。 

    等待获得锁的线程和等待条件对象的线程存在本质上的不同。一旦一个线程调用await方法,它进入该条件的等待集并释放锁。当锁可用时,该线程不能马上解除阻塞。相反,它处于阻塞状态,直到另一个线程调用同一条件上的signalAll方法时为止。这一调用重新激活因为这一条件而等待的所有线程。当这些线程从等待集中移出时,他们再次成为可运行的,调度器将再次激活他们。注意调用signalAll不会立即激活一个线程。它仅仅解除等待线程的阻塞,以便这些线程可以在当前线程退出同步方法之后,通过竞争实现对对象的访问。 

    如果使用锁,就不能使用带资源的try语句。 

    同步阻塞是指在代码中使用synchronized(obj)代码,于是它获得了obj的锁。不管同步方法还是同步阻塞,都是为了互斥访问共享数据。在方法内部使用同步阻塞可以达到每个需要同步处理的方法使用不同的锁的效果,这样虽然可以使得不同线程访问同一对象的不同方法时不会相互锁定,但并不能保证方法内部对于共享数据访问的互斥访问。 

    通过获得一个对象的锁来实现额外的原子操作,称为客户端锁定。客户端锁定可以工作的前提是客户端同步代码中调用到的同步处理方法都使用内部锁,否则就会导致同步失效。所以客户端锁是非常脆弱的,不推荐使用。 

    volatile(不稳定的)关键字为实例域的同步访问提供了一种免锁机制。如果声明一个域为volatile,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。volatile变量不能提供原子性,也就是说这个关键字通知了方法在访问该变量的时候需要更新缓存获取最新数据,但没有办法来保证内部操作的时候不受其他线程影响。 

    ReentrantReadWriteLock适用于很多线程从一个共享数据结构读取数据而很少线程修改数据。在这种情况下,允许对读线程共享访问,而对写线程互斥访问。

    SimpleDateFormat类不是线程安全的,所以在类中使用一个私有的域来保存一个公用的SimpleDateFormat是错误的,而每次进行日期格式转化都new出来新的Format类的代价又很高。应该使用ThreadLocal来包装SimpleDateFormat对象,这样每个转化线程持有自身的Format对象不会有并发问题。个人认为前提是线程是需要复用的,比如使用线程池。否则效果和每次new新的Format对象没有差别。或者如果使用线程池,即便不是用ThreadLocal,而保证每个线程使用自己独立的Format对象也可以。 

    阻塞队列&线程安全集合

    虽然我们可以使用线程、中断、锁等并发程序设计基础的底层构建模块,但对于实际编程来说,应该尽可能远离底层结构。使用由并发处理的较高层次的结构要方便得多,安全得多。

    可以使用同步包装器来把不是线程安全的ArrayList、HashMap等包装成线程安全的,如果在另一个线程可能进行修改时要对集合进行迭代,仍然需要使用客户端锁定。最好使用java.util.concurrent包中定义的集合,不是用同步包装器。 

    其它

    Runnable封装一个异步运行的任务,是一个没有参数和返回值的异步方法。Callable与Runnable类似,但是有返回值。Future用于保存异步计算的结果。 

    执行器(Executor)类用于构建线程池。

    ScheduledExecutorService是一种允许使用线程池机制的java.util.Timer的泛化。 

    Fork-Join框架适用于计算密集型,任务可分级的计算。 

    同步器中有CyclicBarrier、CountDownLatch、Exchange、Semaphore、SynchronousQueue。目前项目只使用过CountDownLatch和Semaphore,CountDownLatch用于将请求调用和结果返回进行异步处理,Semaphore用于在后台系统出现故障时限制并发访问量。

    参考

    Java核心技术(卷1)原书第九版

    http://www.cnblogs.com/onlywujun/p/3565082.html

  • 相关阅读:
    高性能服务器开发基础系列 (二)Reactor模式
    高性能服务器开发基础系列 (二)Reactor模式
    高性能服务器开发基础系列 (二)Reactor模式
    javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    JS基础入门篇(十)— 数组方法
    JS基础入门篇(十)— 数组方法
    C# WinForm 文件上传下载
  • 原文地址:https://www.cnblogs.com/jiaoqq/p/5719086.html
Copyright © 2011-2022 走看看