java多线程发展.docx

上传人:b****0 文档编号:941861 上传时间:2022-10-14 格式:DOCX 页数:38 大小:619.40KB
下载 相关 举报
java多线程发展.docx_第1页
第1页 / 共38页
java多线程发展.docx_第2页
第2页 / 共38页
java多线程发展.docx_第3页
第3页 / 共38页
java多线程发展.docx_第4页
第4页 / 共38页
java多线程发展.docx_第5页
第5页 / 共38页
点击查看更多>>
下载资源
资源描述

java多线程发展.docx

《java多线程发展.docx》由会员分享,可在线阅读,更多相关《java多线程发展.docx(38页珍藏版)》请在冰豆网上搜索。

java多线程发展.docx

java多线程发展

Java多线程发展简史

文章系本人原创,转载请保持完整性并注明出自《四火的唠叨》

这篇文章,大部分内容,是周五我做的一个关于如何进行Java多线程编程的KnowledgeSharing的一个整理,我希望能对Java从第一个版本开始,在多线程编程方面的大事件和发展脉络有一个描述,并且提及一些在多线程编程方面常见的问题。

对于Java程序员来说,如果从历史的角度去了解一门语言一个特性的演进,或许能有不同收获。

 

引言

首先问这样一个问题,如果提到Java多线程编程,你会想到什么?

 

▪volatile、synchronized关键字?

▪竞争和同步?

▪锁机制?

▪线程安全问题?

▪线程池和队列?

好吧,请原谅我在这里卖的关子,其实这些都对,但是又不足够全面,如果我们这样来谈论Java多线程会不会全面一些:

1.模型:

JMM(Java内存模型)和JCM(Java并发模型)

2.使用:

JDK中的并发包

3.实践:

怎样写线程安全的代码

4.除错:

使用工具来分析并发问题

5.……

可是,这未免太死板了,不是么?

不如换一个思路,我们少谈一些很容易查到的语法,不妨从历史的角度看看Java在多线程编程方面是怎样进化的,这个过程中,它做了哪些正确的决定,犯了哪些错误,未来又会有怎样的发展趋势?

另外,还有一点要说是,我希望通过大量的实例代码来说明这些事情。

Linus说:

“Talkischeap,showmethecode.”。

下文涉及到的代码我已经上传,可以在此打包下载。

 

诞生

Java的基因来自于1990年12月Sun公司的一个内部项目,目标设备正是家用电器,但是C++的可移植性和API的易用性都让程序员反感。

旨在解决这样的问题,于是又了Java的前身Oak语言,但是知道1995年3月,它正式更名为Java,才算Java语言真正的诞生。

 

JDK1.0

1996年1月的JDK1.0版本,从一开始就确立了Java最基础的线程模型,并且,这样的线程模型再后续的修修补补中,并未发生实质性的变更,可以说是一个具有传承性的良好设计。

抢占式和协作式是两种常见的进程/线程调度方式,操作系统非常适合使用抢占式方式来调度它的进程,它给不同的进程分配时间片,对于长期无响应的进程,它有能力剥夺它的资源,甚至将其强行停止(如果采用协作式的方式,需要进程自觉、主动地释放资源,也许就不知道需要等到什么时候了)。

Java语言一开始就采用协作式的方式,并且在后面发展的过程中,逐步废弃掉了粗暴的stop/resume/suspend这样的方法,它们是违背协作式的不良设计,转而采用wait/notify/sleep这样的两边线程配合行动的方式。

一种线程间的通信方式是使用中断:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

publicclassInterruptCheckextendsThread{

 

    @Override

    publicvoidrun(){

        System.out.println("start");

        while(true)

            if(Thread.currentThread().isInterrupted())

                break;

        System.out.println("whileexit");

    }

 

    publicstaticvoidmain(String[]args){

        Threadthread=newInterruptCheck();

        thread.start();

        try{

            sleep(2000);

        }catch(InterruptedExceptione){

        }

        thread.interrupt();

    }

}

这是中断的一种使用方式,看起来就像是一个标志位,线程A设置这个标志位,线程B时不时地检查这个标志位。

另外还有一种使用中断通信的方式,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

publicclassInterruptWaitextendsThread{

    publicstaticObjectlock=newObject();

 

    @Override

    publicvoidrun(){

        System.out.println("start");

        synchronized(lock){

            try{

                lock.wait();

            }catch(InterruptedExceptione){

                System.out.println(Thread.currentThread().isInterrupted());

                Thread.currentThread().interrupt();//setinterruptflagagain

                System.out.println(Thread.currentThread().isInterrupted());

                e.printStackTrace();

            }

        }

    }

 

    publicstaticvoidmain(String[]args){

        Threadthread=newInterruptWait();

        thread.start();

        try{

            sleep(2000);

        }catch(InterruptedExceptione){

        }

        thread.interrupt();

    }

}

在这种方式下,如果使用wait方法处于等待中的线程,被另一个线程使用中断唤醒,于是抛出InterruptedException,同时,中断标志清除,这时候我们通常会在捕获该异常的地方重新设置中断,以便后续的逻辑通过检查中断状态来了解该线程是如何结束的。

在比较稳定的JDK1.0.2版本中,已经可以找到Thread和ThreadUsage这样的类,这也是线程模型中最核心的两个类。

整个版本只包含了这样几个包:

java.io、java.util、、java.awt和java.applet,所以说Java从一开始这个非常原始的版本就确立了一个持久的线程模型。

值得一提的是,在这个版本中,原子对象AtomicityXXX已经设计好了,这里给出一个例子,说明i++这种操作时非原子的,而使用原子对象可以保证++操作的原子性:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

importjava.util.concurrent.atomic.AtomicInteger;

 

publicclassAtomicity{

 

    privatestaticvolatileintnonAtomicCounter=0;

    privatestaticvolatileAtomicIntegeratomicCounter=newAtomicInteger(0);

    privatestaticinttimes=0;

 

    publicstaticvoidcaculate(){

        times++;

        for(inti=0;i<1000;i++){

            newThread(newRunnable(){

                @Override

                publicvoidrun(){

                    nonAtomicCounter++;

                    atomicCounter.incrementAndGet();

                }

            }).start();

        }

 

        try{

            Thread.sleep(1000);

        }catch(InterruptedExceptione){

        }

    }

 

    publicstaticvoidmain(String[]args){

        caculate();

        while(nonAtomicCounter==1000){

            nonAtomicCounter=0;

            atomicCounter.set(0);

            caculate();

        }

 

        System.out.println("Non-atomiccounter:

"+times+":

"

                +nonAtomicCounter);

        System.out.println("Atomiccounter:

"+times+":

"+atomicCounter);

    }

}

上面这个例子你也许需要跑几次才能看到效果,使用非原子性的++操作,结果经常小于1000。

对于锁的使用,网上可以找到各种说明,但表述都不够清晰。

请看下面的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

publicclassLock{

    privatestaticObjecto=ne

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1