Android多线程全新讲解Word文件下载.docx

上传人:b****5 文档编号:21066331 上传时间:2023-01-27 格式:DOCX 页数:50 大小:303.64KB
下载 相关 举报
Android多线程全新讲解Word文件下载.docx_第1页
第1页 / 共50页
Android多线程全新讲解Word文件下载.docx_第2页
第2页 / 共50页
Android多线程全新讲解Word文件下载.docx_第3页
第3页 / 共50页
Android多线程全新讲解Word文件下载.docx_第4页
第4页 / 共50页
Android多线程全新讲解Word文件下载.docx_第5页
第5页 / 共50页
点击查看更多>>
下载资源
资源描述

Android多线程全新讲解Word文件下载.docx

《Android多线程全新讲解Word文件下载.docx》由会员分享,可在线阅读,更多相关《Android多线程全新讲解Word文件下载.docx(50页珍藏版)》请在冰豆网上搜索。

Android多线程全新讲解Word文件下载.docx

下面来实现一个简单的定时器,功能如下,每隔2秒执行一次,之后隔4秒执行一次,然后又隔2秒,就这样轮循下去.具体用法可以查看API里面有详细介绍.

[java] 

viewplaincopy

1.public 

static 

void 

main(String[] 

args) 

2. 

new 

Timer().schedule(new 

MyTimerTask(), 

2000);

3. 

try 

4. 

while 

(true) 

5. 

System.out.println(new 

Date().getSeconds());

6. 

Thread.sleep(1000);

7. 

8.} 

catch 

(InterruptedException 

e) 

9. 

e.printStackTrace();

10. 

11. 

12. 

13.class 

MyTimerTask 

extends 

TimerTask 

14. 

int 

count 

0;

15. 

@Override 

16. 

public 

run() 

17. 

(count 

1) 

2;

//count=0或1 

18. 

System.out.println("

boming"

);

19. 

Timer 

timer 

Timer();

20. 

timer.schedule(new 

2000 

(2000) 

count);

21. 

当两个线程去同时操作一个字符串,那么可能会出现线程安全问题.这样的情况可以用银行转帐来解释.

下面的代码就会出现问题,

2.final 

Outputer 

outputer 

Outputer();

3.new 

Thread() 

4.@Override 

5.public 

6.while 

7.try 

8.Thread.sleep(100);

9.} 

10.e.printStackTrace();

11.} 

12.outputer.print("

zhangsan"

13.} 

14.} 

15.}.start();

16.new 

17.@Override 

18.public 

19.while 

20.try 

21.Thread.sleep(100);

22.} 

23.e.printStackTrace();

24.} 

25.outputer.print("

zhangxiaoxiang"

26.} 

27.} 

28.}.start();

29.} 

30.} 

31.class 

32.public 

print(String 

name) 

33.for 

(int 

<

name.length();

i++) 

34.System.out.print(name.charAt(i));

35.} 

36.System.out.println();

// 

打印完字符串换行 

37.} 

38.} 

我们使用两个线程去调用print(Stringname)方法,当第一个方法还没有执行完毕,第二个方法来执行,那么打印出来的name就会出现为问题.如下图所示,

现在我们要实现的是,只有当第一个线程执行完毕后,第二个线程才能执行print(Stringname)方法,这就必须互斥或者说同步.

我们知道实现同步可以使用同步代码块或者同步方法,想到同步(Synchronized)那么自然而然就想到同步监视器.

这是两个很重要的概念.

现在我们来改造上面Outputer的print(Stringname)方法.

2.//synchronized()里面的参数就是同步监视器 

3.//然而这里使用name作为同步监视器是不行的, 

4.//因为要实现原子性(互斥)必须要使用同一个监视器对象 

5.//当第一个线程来执行该代码块,name对象是一个String对象 

6.//当第二个线程来执行,name对象又是另一个String对象, 

7.//这样就不能实现同步 

8.synchronized 

(name) 

9.for 

10.System.out.print(name.charAt(i));

12.System.out.println();

执行结果如下所示:

我们可以通过this关键字作为同步监视器,因为从上面定义两个线程的代码来看,我们只new了一次Outputer对象,所以this代表同一个对象.

现在来通过同步方法来实现同步,

1.//同步方法也同样也有同步监视器,它是this 

2.public 

synchronized 

print2(String 

for 

System.out.print(name.charAt(i));

System.out.println();

7.} 

把第二个线程改成使用print2(Stringname)方法.这样的话就需要print2和print这两个方法互斥.这个怎么理解呢?

上面我们是对print()这个一个方法进行互斥,现在呢?

需要对两个方法进行互斥.

我们可以这样比喻(对一个方法进行互斥):

假设一个茅坑(print(Stringname)),上面有一把锁(this对象),现在一个人(Thread)来上厕所,它把钥匙放进了口袋,第二个人(Thread2)来上厕所,因为没有钥匙,必须要等第一个人出来,把钥匙放上去,第二个人才能拿着钥匙进去.这是对一个方法进行同步,

(对两个方法或者更多进行同步)),现在有多个茅坑(print(Stringname),print2(Stringname)),只有一个钥匙(同步监视器),那么当一个人(Thread)进去后,拿了那仅有的一个钥匙,就算其他人(Thread)想进入的没有人占的茅坑也不行,因为没有钥匙.

这样的话,打印name的时候就不会出现问题.

现在还有一种情况:

1.//静态的同步方法同样也有同步监视器,它是class 

print3(String 

3.for 

4.System.out.print(name.charAt(i));

5.} 

6.System.out.println();

这样的话要想互斥就必须把同步监视器改成Outputer.class了,在内存中只有一份.

线程之间的同步通信

通过一道面试提来解释.

子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。

8.这样的话要想互斥就必须把同步监视器改成Outputer.class了,在内存中只有一份. 

10.线程之间的同步通信 

11.通过一道面试提来解释. 

12.子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。

13.public 

14.new 

Thread(new 

Runnable() 

15.@Override 

16.public 

17.for 

1;

50;

k++) 

18.for 

10;

19.System.out.println("

sub 

thread 

sequence 

"

20.+ 

loop 

of 

k);

21.} 

23.} 

24.}).start();

25.for 

26.for 

100;

27.System.out 

28..println("

main 

31.} 

1. 

这样主要的程序逻辑是实现了,但是执行的次序乱来,子线程执行10次不应该别打断,主线程执行100次也不应该被打断.

所以我们自然就想到了同步,只需要把子循环使用同步代码块,但是用什么作为同步监视器呢?

this显然不行的.当然该类的字节码class是可以的,但是这样有2个问题,

第一,虽然实现了同步,但是,不是子线程一次,主线程一次,所以在子/主(线程)次序上还是乱了.

第二,使用class作为同步监视器不好,如果程序逻辑很复杂,需要多组需要互斥,使用class作为同步监视器,那么就成了一组了.所以这也不好.(关于多组互斥可以查看博客

经验:

要用到共同数据(包括同步锁)或共同算法的若干个方法,应该归在同一个类上,这种设计体现了高内聚和程序的健壮性.

比如:

据此,我们可以这样设计

class 

Business{

publicsynchronizedvoid 

sub(int 

k){

i=1;

i<

=10;

i++){

subthreadsequence"

+i+"

loopof"

+k);

}

main(int 

=100;

mainthreadsequence"

这样就把相关的方法写到一个类里面了.但是这里还是没有解决通信问题.最终代码如下:

publicstaticvoid 

main(String[]args){

final 

Businessbusiness=new 

Business();

Runnable(){

@Override

publicvoid 

run(){

k=1;

k<

=50;

k++){

business.sub(k);

}).start();

business.main(k);

//默认子线程先执行

booleanisShouldSub 

=true;

if(!

isShouldSub){//此处用while最好,因为可能出现假唤醒,//用while的话还会重新判断,这样程序更加严谨和健壮

{

this.wait();

//this表示同步监视器对象

(InterruptedExceptione){

//子线程做完了,把它置为false

isShouldSub 

=false;

//并且唤醒主线程

this.notify();

if(isShouldSub){){//此处用while最好,因为可能出现假唤醒(API文档里有介绍),//用while的话还会重新判断,这样程序更加严谨和健壮

//主线程做完了,把它置为true

//并且唤醒子线程

下面通过一个简单的示例来描述线程之间非共享数据.

1.private 

Random().nextInt();

8. 

System.out.println(Thread.currentThread().getName() 

put 

value 

to 

A().get();

B().get();

13. 

Thread.sleep(10);

20.} 

21.//模块A 

22.static 

23.public 

get() 

24. 

from 

+Thread.currentThread().getName() 

get 

25. 

27.//模块B 

28.static 

29. 

30. 

31. 

32.} 

现在我们需要这样的效果,假设线程0给i赋值为1,那么当线程0取的时候也是1,也就是说线程之间取各自放进去的值.而上面的程序达不到这样的要求.这就需要线程范围内的数据共享.

那么我们可以这样来实现,这也是线程范围内数据共享的原理.

定义一个Map集合key和value分别为Thread和Integer.

把给i赋值的代码替换为

k=new 

map.put(Thread.currentThread(),k);

get()方法内的代码改为

Afrom"

+Thread.currentThread().getName()

getvalue"

map.get(Thread.currentThread()));

这样的话就实现了线程范围内的数据共享了,线程取得值是各自放进去的.

这有什么用呢?

比如事务,所谓事务的回滚和提交指的是在一个线程上的,如果是在不同的线程上,那么逻辑就乱了.这不是我们想要的,这样的话我们就可以通过线程范围内共享数据,也就是把连接绑定到该线程上,那么在该线程获取的连接是同一个连接.

下面通过ThreadLocal来实现这样的功能.

ThreadLocalTest 

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

当前位置:首页 > IT计算机 > 计算机硬件及网络

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

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