Java线程:新特征-原子量

简介:
 
所谓的原子量即操作变量的操作是“原子的”,该操作不可再分,因此是线程安全的。
 
为何要使用原子变量呢,原因是多个线程对单个变量操作也会引起一些问题。在Java5之前,可以通过volatile、synchronized关键字来解决并发访问的安全问题,但这样太麻烦。
Java5之后,专门提供了用来进行单变量多线程并发安全访问的工具包java.util.concurrent.atomic,其中的类也很简单。
 
下面给出一个反面例子(切勿模仿):
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.atomic.AtomicLong; 

/** 
* Java线程:新特征-原子量 

* @author leizhimin 2009-11-6 9:53:11 
*/
 
public  class Test { 
         public  static  void main(String[] args) { 
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Runnable t1 =  new MyRunnable( "张三", 2000); 
                Runnable t2 =  new MyRunnable( "李四", 3600); 
                Runnable t3 =  new MyRunnable( "王五", 2700); 
                Runnable t4 =  new MyRunnable( "老张", 600); 
                Runnable t5 =  new MyRunnable( "老牛", 1300); 
                Runnable t6 =  new MyRunnable( "胖子", 800); 
                 //执行各个线程 
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                 //关闭线程池 
                pool.shutdown(); 
        } 


class MyRunnable  implements Runnable { 
         private  static AtomicLong aLong =  new AtomicLong(10000);         //原子量,每个线程都可以自由操作 
         private String name;                 //操作人 
         private  int x;                             //操作数额 

        MyRunnable(String name,  int x) { 
                 this.name = name; 
                 this.x = x; 
        } 

         public  void run() { 
                System.out.println(name +  "执行了" + x +  ",当前余额:" + aLong.addAndGet(x)); 
        } 
}
 
运行结果:
李四执行了3600,当前余额:13600 
王五执行了2700,当前余额:16300 
老张执行了600,当前余额:16900 
老牛执行了1300,当前余额:18200 
胖子执行了800,当前余额:19000 
张三执行了2000,当前余额:21000 

Process finished with exit code 0
 
张三执行了2000,当前余额:12000 
王五执行了2700,当前余额:18300 
老张执行了600,当前余额:18900 
老牛执行了1300,当前余额:20200 
胖子执行了800,当前余额:21000 
李四执行了3600,当前余额:15600 

Process finished with exit code 0
 
张三执行了2000,当前余额:12000 
李四执行了3600,当前余额:15600 
老张执行了600,当前余额:18900 
老牛执行了1300,当前余额:20200 
胖子执行了800,当前余额:21000 
王五执行了2700,当前余额:18300 

Process finished with exit code 0
 
从运行结果可以看出,虽然使用了原子量,但是程序并发访问还是有问题,那究竟问题出在哪里了?
 
这里要注意的一点是,原子量虽然可以保证单个变量在某一个操作过程的安全,但无法保证你整个代码块,或者整个程序的安全性。因此,通常还应该使用锁等同步机制来控制整个程序的安全性。
 
下面是对这个错误修正:
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
import java.util.concurrent.atomic.AtomicLong; 

/** 
* Java线程:新特征-原子量 

* @author leizhimin 2009-11-6 9:53:11 
*/
 
public  class Test { 
         public  static  void main(String[] args) { 
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Lock lock =  new ReentrantLock( false); 
                Runnable t1 =  new MyRunnable( "张三", 2000,lock); 
                Runnable t2 =  new MyRunnable( "李四", 3600,lock); 
                Runnable t3 =  new MyRunnable( "王五", 2700,lock); 
                Runnable t4 =  new MyRunnable( "老张", 600,lock); 
                Runnable t5 =  new MyRunnable( "老牛", 1300,lock); 
                Runnable t6 =  new MyRunnable( "胖子", 800,lock); 
                 //执行各个线程 
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                 //关闭线程池 
                pool.shutdown(); 
        } 


class MyRunnable  implements Runnable { 
         private  static AtomicLong aLong =  new AtomicLong(10000);         //原子量,每个线程都可以自由操作 
         private String name;                 //操作人 
         private  int x;                             //操作数额 
         private Lock lock; 

        MyRunnable(String name,  int x,Lock lock) { 
                 this.name = name; 
                 this.x = x; 
                 this.lock = lock; 
        } 

         public  void run() { 
                lock.lock(); 
                System.out.println(name +  "执行了" + x +  ",当前余额:" + aLong.addAndGet(x)); 
                lock.unlock(); 
        } 
}
 
执行结果:
张三执行了2000,当前余额:12000 
王五执行了2700,当前余额:14700 
老张执行了600,当前余额:15300 
老牛执行了1300,当前余额:16600 
胖子执行了800,当前余额:17400 
李四执行了3600,当前余额:21000 

Process finished with exit code 0
 
这里使用了一个对象锁,来控制对并发代码的访问。不管运行多少次,执行次序如何,最终余额均为21000,这个结果是正确的。
 
有关原子量的用法很简单,关键是对原子量的认识,原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的。


本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/222541,如需转载请自行联系原作者
相关文章
|
10月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
437 1
|
10月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
405 1
|
11月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
452 0
|
11月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
625 16
|
12月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
12月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
530 83
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
484 0
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
577 83

热门文章

最新文章