java 多线程

理解java多线程,对于java内存模型的理解是必须的。

 

java 内存模型 ( java memory model )
根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。

每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。

 

java的内存模型,要解决两个主要的问题:可见性和有序性。

     何谓可见性? 多个线程之间是不能互相传递数据通信的,它们之间的沟通只能通过共享变量来进行。Java内存模型(JMM)规定了jvm有主内存,主内存是多个线程共享的。当new一个对象的时候,也是被分配在主内存中,每个线程都有自己的工作内存,工作内存存储了主存的某些对象的副本,当然线程的工作内存大小是有限制的。当线程操作某个对象时,执行顺序如下:
 (1) 从主存复制变量到当前工作内存 (read and load)
 (2) 执行代码,改变共享变量值 (use and assign)
 (3) 用工作内存数据刷新主存相关内容 (store and write)

JVM规范定义了线程对主存的操作指令:read,load,use,assign,store,write。当一个共享变量在多个线程的工作内存中都有副本时,如果一个线程修改了这个共享变量,那么其他线程应该能够看到这个被修改后的值,这就是多线程的可见性问题。
     什么是有序性呢 ?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本 (use),也就是说 read,load,use顺序可以由JVM实现系统决定。

 

 

线程状态:

线程的状态转换是线程控制的基础。线程状态总的可分为五大状态:分别是生、可运行、运行、等待/阻塞、死。

 

 

多线程中的经典问题

Double-Checked Locking失效问题

Class Foo
{
     Private Resource res = null;
     Public Resource getResource()
     {
          If (res == null)
          {
            //只有在第一次初始化时,才使用同步方式.
               synchronized(this)
          {
          if(res == null)
          {
               res = new Resource();
          }
          return res;
     }
}
由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将 共享变量的引用指向 部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.

 

DCL的替代 Initialize-On-Demand :

public class Foo {
    // 似有静态内部类, 只有当有引用时, 该类才会被装载
    private static class LazyFoo {
       public static Foo foo = new Foo();
    }
 
    public static Foo getInstance() {
       return LazyFoo.foo;
    }
}
 
volatile关键字

Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。

就是提示VM,对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。 这个编译器不会对此变量的访问做优化,它在效率上会比较低。

 

Sleep 方法调用不释放 锁标志,调用后 其它优先级的线程存在执行的机会。在指定的时间后自动进入可执行状态。

yield  方法调用不释放 锁标志,调用后 同优先级的线程存在执行的机会。自身重新进入可执行状态,线程本身存在马上被执行可能。

wait  方法调用后释放 锁标志,

wai/notify 要对锁标志进行操作,需要在同步块中执行,否则会抛 Runtime 异常。

suspend 方法必须由 resume 方法来唤醒,它也是不释放锁标志的。

 

在给对象加锁的时候,只有对共享变量加锁才是有意义的。

 

 

摘自 :

http://www.javaeye.com/topic/806990

http://kenwublog.com/explain-java-memory-model-in-detail

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值