java多线程Word文档格式.docx

上传人:b****6 文档编号:21808168 上传时间:2023-02-01 格式:DOCX 页数:73 大小:194.85KB
下载 相关 举报
java多线程Word文档格式.docx_第1页
第1页 / 共73页
java多线程Word文档格式.docx_第2页
第2页 / 共73页
java多线程Word文档格式.docx_第3页
第3页 / 共73页
java多线程Word文档格式.docx_第4页
第4页 / 共73页
java多线程Word文档格式.docx_第5页
第5页 / 共73页
点击查看更多>>
下载资源
资源描述

java多线程Word文档格式.docx

《java多线程Word文档格式.docx》由会员分享,可在线阅读,更多相关《java多线程Word文档格式.docx(73页珍藏版)》请在冰豆网上搜索。

java多线程Word文档格式.docx

它区分为synchronized代码块和synchronized方法。

synchronized的作用是让线程获取对象的同步锁。

2.Thread和Runnable

2.1.Thread和Runnable简介

Runnable是一个接口,该接口中只包含了一个run()方法。

它的定义如下:

publicinterfaceRunnable{

publicabstractvoidrun();

}

Runnable的作用,实现多线程。

我们可以定义一个类A实现Runnable接口;

然后,通过newThread(newA())等方式新建线程。

Thread是一个类。

Thread本身就实现了Runnable接口。

它的声明如下:

publicclassThreadimplementsRunnable{}

Thread的作用,实现多线程。

2.2.Thread和Runnable的异同点

Thread和Runnable的相同点:

都是“多线程的实现方式”。

Thread和Runnable的不同点:

Thread是类,而Runnable是接口;

Thread本身是实现了Runnable接口的类。

我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。

此外,Runnable还可以用于“资源的共享”。

即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。

通常,建议通过“Runnable”实现多线程!

2.3.Thread和Runnable的多线程示例

2.4.Thread的多线程示例

下面通过示例更好的理解Thread和Runnable,借鉴网上一个例子比较具有说服性的例子。

1//ThreadTest.java源码

2classMyThreadextendsThread{

3privateintticket=10;

4publicvoidrun(){

5for(inti=0;

i<

20;

i++){

6if(this.ticket>

0){

7System.out.println(this.getName()+"

卖票:

ticket"

+this.ticket--);

8}

9}

10}

11};

12

13publicclassThreadTest{

14publicstaticvoidmain(String[]args){

15//启动3个线程t1,t2,t3;

每个线程各卖10张票!

16MyThreadt1=newMyThread();

17MyThreadt2=newMyThread();

18MyThreadt3=newMyThread();

19t1.start();

20t2.start();

21t3.start();

22}

23}

运行结果:

Thread-0卖票:

ticket10

Thread-1卖票:

Thread-2卖票:

ticket9

ticket8

ticket7

ticket6

ticket5

ticket4

ticket3

ticket2

ticket1

结果说明:

(01)MyThread继承于Thread,它是自定义个线程。

每个MyThread都会卖出10张票。

(02)主线程main创建并启动3个MyThread子线程。

每个子线程都各自卖出了10张票。

2.5.Runnable的多线程示例

下面,我们对上面的程序进行修改。

通过Runnable实现一个接口,从而实现多线程。

1//RunnableTest.java源码

2classMyThreadimplementsRunnable{

7System.out.println(Thread.currentThread().getName()+"

13publicclassRunnableTest{

15MyThreadmt=newMyThread();

16

17//启动3个线程t1,t2,t3(它们共用一个Runnable对象),这3个线程一共卖10张票!

18Threadt1=newThread(mt);

19Threadt2=newThread(mt);

20Threadt3=newThread(mt);

21t1.start();

22t2.start();

23t3.start();

24}

25}

(01)和上面“MyThread继承于Thread”不同;

这里的MyThread实现了Thread接口。

(02)主线程main创建并启动3个子线程,而且这3个子线程都是基于“mt这个Runnable对象”而创建的。

运行结果是这3个子线程一共卖出了10张票。

这说明它们是共享了MyThread接口的。

3.Thread中start()和run()的区别

3.1.start()和run()的区别说明

start():

它的作用是启动一个新线程,新线程会执行相应的run()方法。

start()不能被重复调用。

run() 

run()就和普通的成员方法一样,可以被重复调用。

单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!

下面以代码来进行说明。

classMyThreadextendsThread{

publicvoidrun(){

...

}

};

MyThreadmythread=newMyThread();

mythread.start()会启动一个新线程,并在新线程中运行run()方法。

而mythread.run()则会直接在当前线程中运行run()方法,并不会启动一个新线程来运行run()。

3.2.start()和run()的区别示例

下面,通过一个简单示例演示它们之间的区别。

源码如下:

1//Demo.java的源码

3publicMyThread(Stringname){

4super(name);

5}

6

7publicvoidrun(){

8System.out.println(Thread.currentThread().getName()+"

isrunning"

);

9}

10};

11

12publicclassDemo{

13publicstaticvoidmain(String[]args){

14Threadmythread=newMyThread("

mythread"

15

16System.out.println(Thread.currentThread().getName()+"

callmythread.run()"

17mythread.run();

18

19System.out.println(Thread.currentThread().getName()+"

callmythread.start()"

20mythread.start();

21}

22}

maincallmythread.run()

mainisrunning

maincallmythread.start()

mythreadisrunning

(01)Thread.currentThread().getName()是用于获取“当前线程”的名字。

当前线程是指正在cpu中调度执行的线程。

(02)mythread.run()是在“主线程main”中调用的,该run()方法直接运行在“主线程main”上。

(03)mythread.start()会启动“线程mythread”,“线程mythread”启动之后,会调用run()方法;

此时的run()方法是运行在“线程mythread”上。

3.3.start()和run()相关源码(基于JDK1.7.0_40)

Thread.java中start()方法的源码如下:

publicsynchronizedvoidstart(){

//如果线程不是"

就绪状态"

,则抛出异常!

if(threadStatus!

=0)

thrownewIllegalThreadStateException();

//将线程添加到ThreadGroup中

group.add(this);

booleanstarted=false;

try{

//通过start0()启动线程

start0();

//设置started标记

started=true;

}finally{

if(!

started){

group.threadStartFailed(this);

}

}catch(Throwableignore){

start()实际上是通过本地方法start0()启动线程的。

而start0()会新运行一个线程,新线程会调用run()方法。

privatenativevoidstart0();

Thread.java中run()的代码如下:

publicvoidrun(){

if(target!

=null){

target.run();

target是一个Runnable对象。

run()就是直接调用Thread线程的Runnable成员的run()方法,并不会新建一个线程。

4.synchronized关键字

4.1.synchronized原理

在java中,每一个对象有且仅有一个同步锁。

这也意味着,同步锁是依赖于对象而存在。

当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。

例如,synchronized(obj)就获取了“obj这个对象”的同步锁。

不同线程对同步锁的访问是互斥的。

也就是说,某时间点,对象的同步锁只能被一个线程获取到!

通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。

例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。

假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;

而此时,线程B也企图获取“obj的同步锁”——线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。

4.2.synchronized基本规则

我们将synchronized的基本规则总结为下面3条,并通过实例对它们进行说明。

第一条:

当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

第二条:

当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。

第三条:

当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

4.2.1.第一条

当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

下面是“synchronized代码块”对应的演示程序。

1classMyRunableimplementsRunnable{

2

3@Override

4publicvoidrun(){

5synchronized(this){

6try{

7for(inti=0;

i<

5;

i++){

8Thread.sleep(100);

//休眠100ms

9System.out.println(Thread.currentThread().getName()+"

loop"

+i);

10}

11}catch(InterruptedExceptionie){

12}

13}

14}

15}

17publicclassDemo1_1{

19publicstaticvoidmain(String[]args){

20Runnabledemo=newMyRunable();

//新建“Runnable对象”

21

22Threadt1=newThread(demo,"

t1"

//新建“线程t1”,t1是基于demo这个Runnable对象

23Threadt2=newThread(demo,"

t2"

//新建“线程t2”,t2是基于demo这个Runnable对象

24t1.start();

//启动“线程t1”

25t2.start();

//启动“线程t2”

26}

27}

t1loop0

t1loop1

t1loop2

t1loop3

t1loop4

t2loop0

t2loop1

t2loop2

t2loop3

t2loop4

run()方法中存在“synchronized(this)代码块”,而且t1和t2都是基于"

demo这个Runnable对象"

创建的线程。

这就意味着,我们可以将synchronized(this)中的this看作是“demo这个Runnable对象”;

因此,线程t1和t2共享“demo对象的同步锁”。

所以,当一个线程运行的时候,另外一个线程必须等待“运行线程”释放“demo的同步锁”之后才能运行。

如果你确认,你搞清楚这个问题了。

那我们将上面的代码进行修改,然后再运行看看结果怎么样,看看你是否会迷糊。

修改后的源码如下:

1classMyThreadextendsThread{

7@Override

8publicvoidrun(){

9synchronized(this){

10try{

11for(inti=0;

12Thread.sleep(100);

13System.out.println(Thread.currentThread().getName()+"

15}catch(InterruptedExceptionie){

16}

17}

18}

19}

20

21publicclassDemo1_2{

22

23publicstaticvoidmain(String[]args){

24Threadt1=newMyThread("

//新建“线程t1”

25Threadt2=newMyThread("

//新建“线程t2”

26t1.start();

27t2.start();

28}

29}

代码说明:

比较Demo1_2和Demo1_1,我们发现,Demo1_2中的MyThread类是直接继承于Thread,而且t1和t2都是MyThread子线程。

幸运的是,在“Demo1_2的run()方法”也调用了synchronized(this),正如“Demo1_1的run()方法”也调用了synchronized(this)一样!

那么,Demo1_2的执行流程是不是和Demo1_1一样呢?

如果这个结果一点也不令你感到惊讶,那么我相信你对synchronized和this的认识已经比较深刻了。

否则的话,请继续阅读这里的分析。

synchronized(this)中的this是指“当前的类对象”,即synchronized(this)所在的类对应的当前对象。

它的作用是获取“当前对象的同步锁”。

对于Demo1_2中,synchronized(this)中的this代表的是MyThread对象,而t1和t2是两个不同的MyThread对象,因此t1和t2在执行synchronized(this)时,获取的是不同对象的同步锁。

对于Demo1_1对而言,synchronized(this)中的this代表的是MyRunable对象;

t1和t2共同一个MyRunable对象,因此,一个线程获取了对象的同步锁,会造成另外一个线程等待。

4.2.2.第二条

当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。

1classCount{

3//含有synchronized同步块的方法

4publicvoidsynMethod(){

synMethodloop"

16//非同步的方法

17publicvoidnonSynMethod(){

18try{

19for(inti=0;

20Thread.sleep(100);

21

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

当前位置:首页 > 解决方案 > 其它

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

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