黑马程序员 java学习笔记 Day2:线程

------------android培训java培训、java学习型技术博客、期待与您交流!------------

以前没有写笔记的习惯,现在慢慢的发现及时总结是多么的重要了,呵呵。 

这一篇文章主要关于java多线程,我这个文章主要关于实际的一些问题。同时也算是我以后复习的资料吧,。呵呵大家多多指教。

同时希望多结交一些技术上的朋友。谢谢。


进程:正在执行的程序。每一个进程执行都有一个执行训醒。该顺序是个执行路径,或控制单元。



线程 :就是进程中的一个独立控制单元,线程控制进程的执行。
一个进程,至少是一个线程。


Java VM启动的时会有一个进程 Java.exe,该进程中至少有一个进程,负责Java程序执行。运行代码存在main()方法中。该线程称之为主线程。


扩展:更细节的说明JVM启动不只一个线程,还有负责垃圾回收机制的线程。


1.如何在自定义代码中建立一个线程呢?

通过API的查找,java已经提供了对线程这类事物的描述 Thread类。

创建线程的第一种方法:继承Thread类

    ①.定义类,继承Thread

    ②.复写Thread中的Run方法。目的:将自定义代码存在Run中,让线程运行。

    ③.调用start方法。有2个作用:1"启动线程  2"调用Run方法。

发现运行结果每一次都不同,

因为多个线程都获取cpu的执行权,cpu执行到谁,谁就执行。

明确一点,在某一时刻,只能有一个程序在运行。(多核除外)

cpu在做快速切换,已达到看上去是同时的效果

我们可以形象的把多线程的运行行为看在互相抢夺cpu的执行权。

这就是多线程的特性:随机性谁抢到,谁执行。执行多长时间,cpu说的算。


为什么要覆盖Run方法呢

Thread类用于描述线程,该类就定义了一个功能,用于存储线程要执行的代码。该存储功能就是Run方法。

Thread Run是用于存储线程要运行的代码。

线程都有自己默认的名称。Thread—编号,编号从0开始。用getName();获取

Thread.CurrentThread()==this;

Thread.CurrentThread() 获取当前的进程对象

getName()    获取线程名

setName()  或者    构造函数     设置进程名称


2.创建线程的第二种方法:实现Runnable接口

步骤:

1.定义类实现Runnable接口

2.覆盖Runnable中的Run方法。将线程要运行的代码存放到Run方法中。

3.通过Thread类,创立线程对象

4.将Runnable接口的子类对象作为实际参数传递给Tread类的构造函数。

Why?自定义的Run方法所属的对象是Runnable的子类对象,

  所以,要让进程去执行指定的Run方法,就必须明确Run方法的所属对象。

5.调用Thread类的Start()方法开启线程,并调用Runnable中的Run方法。

★★实现方式和继承方式有什么区别?★★

实现方式,避免了单继承的局限性。在建立线程时,建议使用实现方式。资源独立共享。

2种方式的区别:

线程代码存放的位置不同:继承:Thread子类Run方法中。

实现:接口子类Run方法中。

多线程会出现安全问题,

问题的原因:当多余语句操作共享数据时,一个线程对多条语句只执行一部分,另一个线程参与进来执行,导致共享数据错误。


解决办法:对多余操作共享数据的语句,只能让一个进程都执行完,在执行的过程中,其它进程不可以参与执行。

java对于多线程的安全问题,提供了专业的解决方式———同步代码块

synchronized(对象){  //对象:Object   obj=new  Object();

需要被同步的代码

}

对象如同。持有锁的进程可以在同步中执行。没有锁的线程,即使获取cpu的执行权也进不去,因为没有获取锁。


同步的前提:

1.必须有两个或以上的线程。

2.必须多个线程使用同一个锁。

必须保证同步中只有一个线程,Run方法都放在同步里,相当于单线程。

好处:解决了多线程的安全问题

弊端:多个线程需要判断锁,较为消耗资源。


如何找到问题

1.明确哪些代码是多线程运行代码。

2.明确共享数据。成员都是共享数据

3.明确多线程运行代码中哪些语句是操作共享数据的。

同步函数用的是哪一个锁呢?

函数需要被对象调用,那么还是都有一个所属对象的引用,就是this



懒汉式:



如果同步函数被static修饰后,使用的锁是什么?

通过验证,发现不是this,因为static方法中不可以定义this。

静态进内存中,没有本类对象,但一定有该字节码文件对象  类名.class

静态同步方法使用的锁是该方法所在类的字节码文件对象。

死锁:

同步中嵌套同步,而锁不同就会发生死锁。 


线程间通信:

其实就是多个线程,操作一个资源;但操作的动作不同。


等待唤醒机制: 

wait,notify,notify all。都使用在同步中,需要对持有锁的线程,锁在同步中,所以要使用在同步中,因为只有同步中有锁。


为什么这些操作要定义在Object中呢?

因为这些方法,在操作同步中的线程时,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。

也就是说:等待和唤醒必须是同一把锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object中。


生产者和消费者,为什么要用while判断标记?

原因:让被唤醒的线程再一次判断标记。

为什么用notifyall()?

因为只用notify,容易出现只唤醒本方线程的情况,导致程序中的线程都等待。


await()    signal()   signal all()


JDk1.5中提供了多线程升级解决方案

将同步synchronized替换成实现lock操作

将Object中的wait,notify,notify all替换了condition对象。

该对象可以Lock锁获取。

在该事例中,实现了只唤醒对方的操作

释放锁的动作一定要执行 finally


stop方法已过时

如何停止线程?只有一种,run方法结束

开启多线程运行,运行代码通常都是循环结构

只要控制住循环,就可以让run方法结束,也就是线程结束。

特殊情况:当线程处于冻结状态,就不会读取标记,那么线程就不会结束


interrupt()

当没有指定方式让冻结的线程回复到运行状态时,这时就需要对运行状态进行清除,强制让线程恢复到运行状态中来,这样就是可以操作标记让线程停下来。


setDeamon

join。当A线程执行到b.join()时,那么A线程等待,等B线程执行完,A才会执行,用于临时加入线程。


toString()优先级

yield()暂停







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值