您的位置:首页 > 编程语言 > Java开发

Java 并发0

2015-07-03 18:49 471 查看
http://tutorials.jenkov.com/java-concurrency/concurrency-models.html

单核-单任务-多任务

“并发”并不仅仅指多线程,还可以是多任务,分布式系统。

多线程的好处:

更好的系统资源利用;相近的设计;更好地响应速度。

多线程的代价:

复杂的设计;上下文切换开销;线程自身的资源消费。

并发模型

并发模型指定系统中的线程怎么合作完成给定的任务,不同的模型有不同的划分任务,线程间通信和合作的方式。

Parallel Workers



Assembly Line



Functional Parallelism

Concurrency vs. Parallelism

并发(concurrency):同时处理多个(不相关的)task,比如在单核cpu上,做不到同时“执行”多个task,但可以同时“处理”多个task。

并行(parallelism):将一个task分成多个subtask同时执行,在单核cpu上是无法并行的。

一个应用可以只并发不并行,只并行不并发,既不并行也不并发,既并发也并行。

并发是逻辑上的同时进行,并行侧重物理上的同时进行。

(distributed)分布式在并行处理的基础上,强调正在执行任务的物理设备,如处理器、内存等等硬件,在物理上是分开的。

Creating and Starting Java Threads

调用Thread的start()方法会最终调用run()方法。

public void run() {
        if (target != null) {
            target.run();
        }
    }


所以,重写Thread的run方法或者在Thread的构造方法中传入Runnable实例都可以。

注意,执行调用Thread的start方法才会开启新的线程。如果直接调用run()方法,run中的代码也会被执行,但就不在新的线程中执行了,而是在创建该Thread实例的线程中执行。

public class ThreadExample {

  public static void main(String[] args){
    System.out.println(Thread.currentThread().getName());
    for(int i=0; i<10; i++){
      new Thread("" + i){
        public void run(){
          System.out.println("Thread: " + getName() + " running");
        }
      }.start();
    }
  }
}

注意,上面例子中,尽管是按1,2,3等的顺序start的Thread的,但被执行的顺序不一定是这个顺序,jvm或者操作系统决定到底哪个线程被执行,与它们start的顺序无关。

Race Conditions and Critical Sections

一个程序内,多个线程各跑各的并不会产生问题,只有访问共享资源(内存,文件,数据库,webservice)时,严格说是同时“读”时,才会导致问题。

race condition:当2个线程访问同样的资源,对资源的访问顺序能导致不同的结果,这种情形被称为“竞争条件”。

critical section:导致race condition的代码,称为critical section。

在critical section上使用恰当的线程同步机制可以避免race condition。

Thread Safety and Shared Resources

被多线程访问的代码是安全的代码称为线程安全的。线程安全的代码不会发生race condition。

local variable ,在当前线程栈中,是线程安全的。

local object reference , 只在创建它的线程中使用,传递是线程安全的,如果传递给了别的线程,就不安全了。

If a resource is created, used and disposed within
the control of the same thread,
and never escapes the control of this thread,
the use of that resource is thread safe.

注意,要区分一个对象是资源本身还是只是对资源的引用,如果只是对资源的引用,那即使对象是安全的,实际上还是不安全的。

Thread Safety and Immutability

race condition发生在当多个线程访问共享资源,且更新资源的情况下,那如果资源是不可更改的,即 immutability的,那就自然而然线程安全了。

public class ImmutableValue{

  private int value = 0;

  public ImmutableValue(int value){
    this.value = value;
  }

  public int getValue(){
    return this.value;
  }
}

因为value的值是通过构造函数传递进去的,没有set方法,其值是不可被改变的。

public class ImmutableValue{

  private int value = 0;

  public ImmutableValue(int value){
    this.value = value;
  }

  public int getValue(){
    return this.value;
  }

  
      public ImmutableValue add(int valueToAdd){
      return new ImmutableValue(this.value + valueToAdd);
      }
  
}

add方法是通过创建并返回了一个新的对象,并不是在原来对象基础上add的。

public class Calculator{
  private ImmutableValue currentValue = null;

  public ImmutableValue getValue(){
    return currentValue;
  }

  public void setValue(ImmutableValue newValue){
    this.currentValue = newValue;
  }

  public void add(int newValue){
    this.currentValue = this.currentValue.add(newValue);
  }
}

注意,通过immutable达到线程安全时,如果类是immutable,但对类的使用不一定是线程安全的,如上例,可以通过关键字synchronized来搞定这种情况。

Java Memory Model





基础类型的local variable存放在thread stack中

对象存放在共享的heap中,对象的引用存放在thread stack中

调用对象的方法,方法中的local variable存放在thread stack中

对象的member variable,不管是primary type 还是object,都随对象存放在heap中

只有local variable存放在thread stack中



能产生上图的代码:

public class MyRunnable implements Runnable() {

    public void run() {
        methodOne();
    }

    public void methodOne() {
        int localVariable1 = 45;

        MySharedObject localVariable2 =
            MySharedObject.sharedInstance;

        //... do more with local variables.

        methodTwo();
    }

    public void methodTwo() {
        Integer localVariable1 = new Integer(99);

        //... do more with local variable.
    }
}

public class MySharedObject {

    //static variable pointing to instance of MySharedObject

    public static final MySharedObject sharedInstance =
        new MySharedObject();

    //member variables pointing to two objects on the heap

    public Integer object2 = new Integer(22);
    public Integer object4 = new Integer(44);

    public long member1 = 12345;
    public long member1 = 67890;
}


(以后写代码看代码,要想象下它们在内存中的位置)

Hardware Memory Architecture







当左边的cpu改变了obj.count的值后,没有flush back到 main memory,那右边的cpu就不知道这个值改变了,也就是对其是不可见的。可以使用volatile关键字,使直接从main memory读和直接写。



上图发生了race condition,可以使用synchronized代码块避免,synchronized代码块可以保证同一时刻只有一个线程能访问critical section,而且是直接从main memory读取,当thread退出critical section时,将所有更新的variable flush back to main memory,不管变量所否是volatile的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: