Java多线程-2 基本线程间通信 && volatile keyword

这里是通过在主线程中终止一个用户线程的操作的例子。但在本内容之前需要首先了解Java内存模型。

java内存模型

[这里是关于java内存模型的详细资料,但全部是英文的,如果不想细看,可以看我的简略理解����](http://tutorials.jenkov.com/java-concurrency/java-memory-model.html)
java内存模型指定了Java虚拟机如何和计算机的实际内存RAM是如何运作的。
  • 逻辑角度的java内存模型

    java内存模型把内存分为线程栈和堆。
    其中,栈中存有该线程方法调用信息;被该线程调用方法的局部变量;所有基本类型(boolean, byte,short, char,int,long,float,double)的局部变量都存在栈上。
    堆中包含应用中所有线程创建的所有对象。
    具体而言:
  • 基本类型的局部变量:这种局部变量完全保存在线程栈上。
  • 对象引用类型的局部变量:对象的引用(局部变量)被存在线程栈上,但对象本身存放位置是堆上。
  • 对象所包含方法的局部变量:这些方法的局部变量存放在线程栈上。
  • 对象的成员变量和对象本身都被存放在堆上。无论成员变量是基本数据类型还是引用数据类型都是如此。
  • 静态类型的类变量和类的定义本身都被存放在堆上。
//上述内容对应的代码段
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;
}

计算机内存模型

Java内存模型和计算机内存架构的对应
硬件内存并不区分堆内存还是栈内存。堆和栈内存都位于主存中,部分存在CPU的cache和CPU寄存器中。

当对象和变量存放在计算机的不同内存区域时,出现了2个主要问题。

  1. 共享变量更新时的可见性问题,即visibility.
    a). 发生条件:2个或多个线程共享一个对象时,如果未能正确使用volatile关键字或合适的同步机制,一个线程对共享对象所做的更新操作可能对于其他线程并不可见。
    b). 实例:
  2. 共享变量读、检查、写时的竞争条件问题。
    a). 发生条件:2个或多个线程共享一个对象时,多于一个线程更新共享对象的变量时,竞争条件就可能发生。
    b). 实例:

Java volatile 关键字

Java volatile关键字保证了不同线程间对于变量修改结果的可视性问题。
![Visibility](http://img.blog.csdn.net/20170603183342221?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG9zZWVrdHJ1dGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
public class SharedObject {

    public volatile int counter = 0;

}

如果线程间共享变量未被声明为:volatile,则无法保证何时变量counter从CPU cache中被写入主存。这意味着:CPU cache中的counter可能和主存中的值不一样。

package com.fqy.cave;

import java.util.Scanner;

class Processor extends Thread {
    // volatile keyword here is to ensure visibility
    private volatile boolean running = true;

    @Override
    public void run() {
        while (running) {
            System.out.println(Thread.currentThread().getName() + " Hello, Concurrent Programming!");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void shutdown() {
        running = false;
    }
}

/* * 多线程共享同一对象时,一个线程对线程所做的修改可能对于其他线程不可见! 本例中有2个线程;主线程和用户线程p, 如果没有volatile关键字, * 主线程对于boolean变量running的操作可能对于用户线程不可见。 */
public class Cache {
    public static void main(String[] args) {
        Processor p = new Processor();
        p.start();
        System.out.println("Press enter to stop executing...");
        Scanner scanner = new Scanner(System.in);
        scanner.nextLine();
        scanner.close();
        p.shutdown();
        System.out.println(Thread.currentThread().getName() + " terminated another thread!");

    }
}

运行结果:

Thread-0 Hello, Concurrent Programming!
Press enter to stop executing...
Thread-0 Hello, Concurrent Programming!
Thread-0 Hello, Concurrent Programming!

main terminated another thread!

For more content, please click this.

你可能感兴趣的:(多线程,通信,volatile,java内存模型,race-condi)