当前位置:编程学习 > JAVA >>

Java多线程发展简史

引言
首先问这样一个问题,如果提到Java多线程编程,你会想到什么?
● volatile、synchronized关键字?
● 竞争和同步?
● 锁机制?
● 线程安全问题?
● 线程池和队列?
好吧,请原谅我在这里卖的关子,其实这些都对,但是又不足够全面,如果我们这样来谈论Java多线程会不会全面一些:
1.模型:JMM(Java内存模型)和JCM(Java并发模型)
2.使用:JDK中的并发包
3.实践:怎样写线程安全的代码
4.除错:使用工具来分析并发问题
5.……
可是,这未免太死板了,不是么?
不如换一个思路,我们少谈一些很容易查到的语法,不妨从历史的角度看看Java在多线程编程方面是怎样进化的,这个过程中,它做了哪些正确的决定,犯了哪些错误,未来又会有怎样的发展趋势?
另外,还有一点要说是,我希望通过大量的实例代码来说明这些事情。Linus说:“Talk is cheap, show me the code.”。下文涉及到的代码我已经上传,可以在此打包下载。
诞生
Java的基因来自于1990年12月Sun公司的一个内部项目,目标设备正是家用电器,但是C++的可移植性和API的易用性都让程序员反感。旨在解决这样的问题,于是又了Java的前身Oak语言,但是知道1995年3月,它正式更名为Java,才算Java语言真正的诞生。
JDK 1.0
1996年1月的JDK1.0版本,从一开始就确立了Java最基础的线程模型,并且,这样的线程模型再后续的修修补补中,并未发生实质性的变更,可以说是一个具有传承性的良好设计。
抢占式和协作式是两种常见的进程/线程调度方式,操作系统非常适合使用抢占式方式来调度它的进程,它给不同的进程分配时间片,对于长期无响应的进程,它有能力剥夺它的资源,甚至将其强行停止(如果采用协作式的方式,需要进程自觉、主动地释放资源,也许就不知道需要等到什么时候了)。Java语言一开始就采用协作式的方式,并且在后面发展的过程中,逐步废弃掉了粗暴的stop/resume/suspend这样的方法,它们是违背协作式的不良设计,转而采用wait/notify/sleep这样的两边线程配合行动的方式。
一种线程间的通信方式是使用中断:
 
public class InterruptCheck extends Thread {
 
    @Override
    public void run() {
        System.out.println("start");
        while (true)
            if (Thread.currentThread().isInterrupted())
                break;
        System.out.println("while exit");
    }
 
    public static void main(String[] args) {
        Thread thread = new InterruptCheck();
        thread.start();
        try {
            sleep(2000);
        } catch (InterruptedException e) {
        }
        thread.interrupt();
    }
}
这是中断的一种使用方式,看起来就像是一个标志位,线程A设置这个标志位,线程B时不时地检查这个标志位。另外还有一种使用中断通信的方式,如下:
 
public class InterruptWait extends Thread {
    public static Object lock = new Object();
 
    @Override
    public void run() {
        System.out.println("start");
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().isInterrupted());
                Thread.currentThread().interrupt(); // set interrupt flag again
                System.out.println(Thread.currentThread().isInterrupted());
                e.printStackTrace();
            }
        }
    }
 
    public static void main(String[] args) {
        Thread thread = new InterruptWait();
        thread.start();
        try {
            sleep(2000);
        } catch (InterruptedException e) {
        }
        thread.interrupt();
    }
}
在这种方式下,如果使用wait方法处于等待中的线程,被另一个线程使用中断唤醒,于是抛出InterruptedException,同时,中断标志清除,这时候我们通常会在捕获该异常的地方重新设置中断,以便后续的逻辑通过检查中断状态来了解该线程是如何结束的。
在比较稳定的JDK 1.0.2版本中,已经可以找到Thread和ThreadUsage这样的类,这也是线程模型中最核心的两个类。整个版本只包含了这样几个包:java.io、 java.util、java.net、java.awt和java.applet,所以说Java从一开始这个非常原始的版本就确立了一个持久的线程模型。
值得一提的是,在这个版本中,原子对象AtomicityXXX已经设计好了,这里给出一个例子,说明i++这种操作时非原子的,而使用原子对象可以保证++操作的原子性:
 
import java.util.concurrent.atomic.AtomicInteger;
 
public class Atomicity {
 
    private static volatile int nonAtomicCounter = 0;
    private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);
    private static int times = 0;
 
    public static void caculate() {
        times++;
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    nonAtomicCounter++;
                    atomicCounter.incrementAndGet();
                }
            }).start();
        }
 
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
    }
 
    public static void main(String[] args) {
        caculate();
        while (nonAtomicCounter == 1000) {
            nonAtomicCounter = 0;
      &nb

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,