Java并发

来源:互联网 发布:公司美工属于什么部门 编辑:程序博客网 时间:2024/06/16 04:33

Java并发(concurrency)快速入门,想吗?

  • 概述
  • 创建一个多线程程序
    • 1 Thread和Runnable
    • 2 线程的创建及运行
    • 3 简单同步机制
  • 总结

1. 概述


照例先啰嗦几句。
编程是一门艺术,而并发式编程晚于程序语言出现的,并且可以说是计算机问世至今无法取代的艺术精品。
在很久之前没有多核处理器的时候,程序员也好,科研人员也罢,无不在疯狂的攫取着单核处理器的潜在价值,直到单核处理器性能已经被榨取的差不多了,多核处理器的研究才开始再次被提上日程,这时候,另一个概念开始出现并崛起——并行。

NOTE:
并发是多个程序宏观上同时在推进,而并行则是讲究微观上多个程序同时推进,实现并行需要多个处理器(多核处理器)。
与类型变量和类型参数相似,很多程序员将并发和并行混为一谈,并不多加区分。

并发的内容其实有很多,仅一篇文章肯定是讲不了太多内容的,所以本文侧重于并发编程的入门,日后逐渐提高深度,主要大纲如下:

  1. 并发快速入门
  2. 线程间协同(Synchronized)工作
  3. 锁(Lock
  4. 原子变量(Atomic Variables
  5. 线程池(Thread Pools

期间的细枝末节就暂不在此赘述了,直接开始本文的内容了。

2. 创建一个多线程程序


2.1 Thread和Runnable

Thread和Runnable都能完成多线程,但是后者用的较为广泛,原因则先不说,先解读这俩玩意儿:

  1. Thread是一个类,通过继承该类可以直接实现线程的创建和管理new SubThread( ),也可以用以作为executor的传入参数。
  2. Runnable是一个接口,内部只有一个run( )方法,需要通过创建Thread类对象来实现new Thread(new Runnable( )) 线程的创建和管理。

讲到这儿,原因就已经清楚了,Java是单继承模式,这意味着一旦继承了其他类(Thread类),便不能再继承Thread类(其他类),而Java却是可以实现多个接口的,多实现一个少接口或是少实现一个接口,问题不大。

2.2 线程的创建及运行

知道Thread类和Runnable接口还不够,通过一个例子了解具体的创建方法:
示例程序

public class SubThread extends Thread {    private int i;    public SubThread(int i) {        this.i = i;    }    public void run() {        System.out.println("Thread " + this.i + " has created!");    }    public static void main(String[] args) {        new SubThread(1).start();        new SubThread(2).start();    }}

在本段程序中,采取直接继承Thread类的方法进行线程的创建和管理,new SubThread() 为实例化本类对象,也即创建了一个线程,start() 则是启动该线程的方法。
另外,在运行时会发现run方法打印的值顺序每次都可能不同,这是由于并发是多个程序宏观上的推进,但实际上由于共享处理器,处理器的调度算法决定如何分配CPU的时间片到各个线程。过程如图:
交叉执行

示例程序

public class NewRunnable implements Runnable {    private int i;    public NewRunnable(int i) {        this.i = i;    }    public void run() {        System.out.println("Thread " + this.i + " has created!");    }    public static void main(String[] args) {        new Thread(new NewRunnable(1)).start();        new Thread(new NewRunnable(2)).start();//需要通过创建Thread类对象,并将实现了Runnable接口的类对象作为参数传递给Thread(Runnable target)构造器    }}

通过这段程序就可以看出实现Runnable接口的类是如何创建新的线程,以及创建方式与继承Thread类的创建方式有什么不同了。
还有一种使用匿名内部类的方式

new Thread(new Runnable() {            public void run() {                System.out.println("you");            }        }).start();

2.3 简单同步机制

感觉话是不是多了点?不过似乎是没什么废话吧……
在上文的示例中可以看到有一个实例域 i,假如对某个实例对象的实例域进行运算,如自增,自减运算,会不会出现什么问题呢?比如说自增,自减在两个不同的方法中,而两个不同的线程又同时调用出现调用这两个方法的情况,最后i的值是多少,是不是所预期的结果?
答案很显然,不一定。前文表述过,并发程序是交叉执行的,也就是说如果有一个打印操作需要在自增之后自减之前,但是由于线程运行的不受控,所以可能会出现在自增和自减操作执行结束后才开始进行打印操作,结果非预期,但是synchronized方法却可以简单有效的规避这种问题。

public class SynchronizedCounter {    private int c = 0;    public synchronized void increment() {        c++;    }    public synchronized void decrement() {        c--;    }    public synchronized int value() {        return c;    }}

同一个实例对象是禁止同时调用多个synchronized修饰的方法的,如此便避免了之前所提到的问题。

3. 总结


没有这个总结,总感觉有些奇怪。
并发绝不仅仅是Java语言独有的,本文仅针对Java语言进行一个简单的介绍,浏览完本文,创建一个简单的多线程的程序,还不是手到擒来的事情嘛,在这一点上,笔者还是能打包票的。

前文所列的主要纲要日后会继续深入完善并补上博文链接,以供日后的阅读。

0 0
原创粉丝点击