现在的位置: 首页 > 编程语言 > Java > 正文

java-多线程深入(二)互斥性和可见性

2015年01月26日 Java ⁄ 共 1752字 ⁄ 字号 暂无评论

(一)互斥性

互斥性,即原子性。原子,指最小的物质,具体不可再分性。

CPU运算中,对多线程进行时间片分割执行,一个程序块执行时不可分割,即满足互斥性原子性。

java中保证互斥性的方法:

1.用sychronized锁住程序块,实行互斥

synchronized (lock) {  
    a++;
}

2.用Atomic对变量操作实行互斥

public final static AtomicInteger TEST_INTEGER = new AtomicInteger(1);  
      
    public static void main(String []args) throws InterruptedException {  
        final Thread []threads = new Thread[20];  
         for(int i = 0 ; i < 20 ; i++) {  
             final int num = i;  
             threads[i] = new Thread() {  
                 public void run() { 
                    int now = TEST_INTEGER.incrementAndGet();  
                    System.out.println("我是线程:" + num + ",我得到值了,增加后的值为:" + now);  
                 }  
             };  
             threads[i].start();  
         }  
         for(Thread t : threads) {  
             t.join();  
         }  
         System.out.println("最终运行结果:" + TEST_INTEGER.get());  
    }  

TEST_INTEGER在多线程操作中,最终结果不会出现偏差。

JDK的文档中说:“设计原子类主要用作各种块,用于实现非阻塞数据结构和相关基础结构类。compareAndSet()方法不是锁定的常规替换方法。仅当对象的重要更新限于单个变量时才应用它”。


(二)可见性

cpu和内存速度相差过高,引入缓存(cache、寄存器等);一个线程由线程id、指令计数器PC、寄存器集合和堆栈构成,详见《程序员的自我修养》

每个线程有自己的工作内存,修改进程主内存的值,都需要拷贝到工作内存修改后,再回写,其他线程可能出现,读取到未回写的脏数据这种情况。

/**
 * 多线程可见性测试
 * 
 * @author peter_wang
 * @create-time 2015-1-12 下午3:56:29
 */
public class ThreadVisableDemo {
    private static int a = 0;

    static class GetNumThread
        extends Thread {
        @Override
        public void run() {
            System.out.println(a);//B1
        }
    }

    static class ChangeNumThread
        extends Thread {
        @Override
        public void run() {
            a = 1;//A1,A2
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        GetNumThread getNumThread = new GetNumThread();
        ChangeNumThread changeNumThread = new ChangeNumThread();
        changeNumThread.start();//C1
        getNumThread.start();//C2
    }

}

执行结果:输出0或者1


A1读取完数据进行操作,写入到线程A工作内存写缓存中,不一定实时刷新主内存中a的值,B1可能读取到旧数据。

java中保证可见性的方法:

1.用sychronized锁住程序块,实行互斥

static class GetNumThread
        extends Thread {
        @Override
        public void run() {
            synchronized (ThreadVisableDemo.class) {
                System.out.println(a);// B1
            }
        }
    }

    static class ChangeNumThread
        extends Thread {
        @Override
        public void run() {
            synchronized (ThreadVisableDemo.class) {
                a = 1;// A1,A2
            }
        }
    }

2.使用volatile,保证变量可见性

private static volatile int a = 0;

3.使用Atomic对变量操作,实现可见性