java多线程Word文档格式.docx
- 文档编号:21808168
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:73
- 大小:194.85KB
java多线程Word文档格式.docx
《java多线程Word文档格式.docx》由会员分享,可在线阅读,更多相关《java多线程Word文档格式.docx(73页珍藏版)》请在冰豆网上搜索。
它区分为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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 多线程