再谈线程

来源:互联网 发布:淘宝直通车怎么卡位 编辑:程序博客网 时间:2024/05/02 04:53

1 .创建线程的两种方式中,应该优先选择使用实现了Runnable接口的方式,并重写内部的Run方法。

2. 优点在于:可以实现多继承,可以共享实现了Runnable接口的类中的变量或者说是属性


3. 当主线程结束的时候,其他线程不受影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受主线程的影响


4. 前台线程创建的子线程默认是前台线程,后台线程创建的线程默认是后台线程,所有的前台线程死亡后,JVM会通知所有的后台线程死亡

5. sleep方法常常用来暂停调用该方法的线程暂停执行


6. 实际上,当调用了某个线程的yield方法后,只有优先级与当前线程相同,或者优先级比当前线程更高的就绪状态的线程才会获得执行的机会,也包括该线程本身

7. sleep方法比yield方式有更好的可移植性,通常不要依赖yield方法来控制并发线程的执行:因为sleep方法是让当前正在占据cpu的线程暂停执行,而一般对但cpu的计算机来说,会默认使用sleep方法,而不必指定调用哪个线程的sleep方法,因为默认情况下只有一个线程在cpu上运行,所以sleep方法可以放在其他任何有必要暂停执行当前线程的地方,而yield方法必须指定调用它的具体的哪一个线程类,因此相比较sleep而言,它的可移植性相对较差

 


8. 每个线程的默认的优先级都与创建它的父线程,在默认情况下,main线程具有普通优先级,由main线程创建的子线程也有普通优先级。

9. 任何时刻只能有一条线程可以回的对同步监视器的锁定,当同步代码块执行结束后,该线程自然释放了对该同步监视器的锁定。

10. 虽然java程序允许任何对象类作为同步监视器,但是思考一下同步监视器目的:阻止两条线程对同一个共享资源进行并发访问。因此通常推荐使用可能被并发访问的共享资源充当同步监视器。


11. 对于同步方法而言,无需显示指定同步监视器,同步方法的同步监视器是this,也就是该对象本身。

12. 线程安全的类具有如下特征:
 1.该类的对象可以被多个线程安全的访问
 2.每个线程调用该对象的任意方法之后都将得到正确结果。
 3.每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态
其中不可变类总是线程安全的,而可变对象需要额外的方法来保证其线程安全。

 

13. 可变类的线程安全是以降低程序的运行效率作为代价的,为了减少线程安全所带来的负面影响,程序可以采用如下策略:
 1.不要对线程安全类的所有的方法都进行同步,只对那些会改变竞争资源(竞争资源也就是共享资源)的方法进行同步。
 2.如果可变类有两种运行环境:单线程环境和多线程环境,则应该为该可变类提供两种版本: 线程不安全版本和线程安全版本。在单线程环境中使用线程不安全版本以保证性能,在多线程环境中使用线程安全版本。

 

14. 使用ThreadLocal类,它代表一个线程局部变量,通过把数据放在ThreadLocal类中就可以让每条线程创建一个该变量的副本,从而避免并发访问的线程安全问题,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象与线程相关的状态使用ThreadLocal保存;通常我们认为:如果需要进行多个线程之间共享资源,以达到线程之间的通信功能,就使用同步机制;如果仅仅需要隔离多个线程之间的共享冲突,就可以考虑使用ThreadLocal类

15. 如果需要把某个集合包装成线程安全的集合,则应该在创建之后立即包装,以防忘记包装而造成不必要的麻烦

16. 当我们使用java.util包下的Collection作为集合对象时,如果该集合对象创建迭代器后集合元素发生改变,将会引发ConcurrentModificationException。
 

17.如果你发现多线程出现效率问题,你就要检查以下几点:

              1. 是否充分调用了sleep(),yield(),wait()?

              2. 调用sleep()方法的时间是否够长?

              3. 是否执行了过多的线程?

              4. 是否试过其他不同的平台或JVM

18.何时去掉synchronized关键字较为合适?

很简单,只要你确定移除synchronized关键字后的代码段保证不会产生线程同步问题,并且移除synchronized关键字后带来效率方面极为明显的改善时,那么你就可以考虑将synchronized关键字移除,否则,最后不要这么做。但如果你省略关键字synchronized纯碎只是为了避免某个函数称为效能上的瓶颈,这将可能引发资源冲突并引爆灾难。

 

19. 注意:synchronized关键字并不会被继承下去——也就是说即使某个函数在base class中被声明为synchronized,它在derived class中的复写版本并不会自动称为synchronized.

                      

20.关于yield方法的使用:对正在执行的线程有效;若就绪队列中有与当前线程同优先级的排队线程,则当前线程让出cpu控制权,移到队尾,若队列中没有同优先级的线程,忽略此方法。 

 

21.Thread.sleep(1000);  //再此期间,低优先级的线程也可以获得执行

      Thread.yield();     //同优先级的线程可以获得执行

      suspend();    //暂停线程的执行

22  在高并发且以读为主的应用场景中,CopyOnWriteArrayList要优于Vector。但是,当写操作也很频繁时,CopyOnWriteArrayList效率并不高,所以应该优先使用Vector。如果需要一个能够在高并发是仍然能保持良好性能队列,可以使用ConcurrentLinkedQueue对象。


23. BlockingQueue是一种阻塞式的队列,它的主要功能并不是在于提高并发时的队列性能,而在于简化多线程之间的数据共享,典型的使用场景是在生产者和消费者模式中实现数据共享。


24. double和lang类型变量的非原子处理:如果一个double或者Long变量没有声明为volitile,则变量在进行read或write操作时,主内存把它当作两个32位的read或write操作进行处理,这两个操作在时间上是分开的,肯会有其他操作介于它们之间。如果这种情况发生,则两个并发的线程对共享的非volatile类型的double或long变量赋不同的值,那么随后对改变量的使用而获取的值可能不等于任何一个线程所赋的值,而可能是依赖于具体应用的两个线程所赋予的值的混合。因此,在32为的系统中,必须对double或者long进行同步。


25.  java.util.concurent.atomic包中的原子类是基于无锁算法实现的,它们的性能要远远优于普通的有锁操作。因此,推荐直接使用这些工具。

26. 注意区分线程死锁和线程阻塞的概念。线程死锁是指两个或多个线程在等待对方的同步监视器时而发生额互相等待的状况;而线程阻塞是指线程得不到某种资源或者是其他的一些原因而导致其不能继续运行并被推入阻塞队列。严格意义上说,线程死锁是线程阻塞的一种特殊情况。

 

 

 

原创粉丝点击