Java多线程学习记录

来源:互联网 发布:知乎 清华经管 编辑:程序博客网 时间:2024/06/05 03:35
java多线程
1 线程模型
1.1线程优先级
   ·线程自愿地放弃控制:线程显式地放弃控制权、休眠或在I/O之前阻塞,都会
   出现这种情况。在这种情况下,检查所有其他线程,并且准备运行的线程中
   优先级最高的那个线程会获得资源。
   ·线程被优先级更高的线程取代。对于这种情况,没有放弃控制权的低优先级
   线程不管正在做什么,都会被高优先级线程简单地取代。基本上,只要高优
   先级线程希望运行,他就会取代低优先级线程,这称为抢占式多任务处理。


如果具有相同优先级的两个线程竞争cpu资源,这种情况有些复杂。对于windows这
类操作系统,优先级相等的线程以循环方式自动获得cpu资源。对于其他类型的操
作系统,优先级相等的线程以循环方式自动获得cpu资源。对于其他类型的操作系统,
优先级相等的线程必须自愿的向其他线程放弃控制权,否则其他线程就不能运行。


警告:操作系统以不同的方式对具有相等优先级的线程进行上下文切换,可能会
引起可以执行问题。


1.2 同步
1.3 消息传递
    java的消息传递系统允许某个线程进入对象的同步方法,然后进行等待,直到
    其他线程显式地通知这个线程退出为止。
1.4 Thread类和Runnable接口
    Java的多线程系统是基于Thread类、Thread类的方法及其伴随接口Runnable而构建
    的。
    Thread类封装了线程的执行。因为不能直接引用正在运行的线程的细微状态,
    所以需要通过代理进行处理,Thread实例就是线程的代理。
    为了创建新线程,程序可以扩展Thread类或实现Runnable接口。
    
    Thread类定义的一些方法:
getName() 获取线程的名称
getPriority() 获取线程的优先级
isAlive() 确定线程是否仍然在运行
join() 等待线程终止
run() 线程的入口点
sleep() 挂起线程一段时间
start() 通过调用线程的run()方法启动线程


2 主线程
·其他子线程都是从主线程产生的。
·通常,主线程必须是最后才结束执行的线程,因为它要执行各种关闭动作。
尽管主线程是在程序启动时自动创建的,但是可以通过Thread对象对其进行控制。
为此,必须调用currentThread()方法获取对主线程的一个引用。该方法是Thread类
的共有静态成员,它的一般形式如下所示:
static Thread currentThread()
该方法返回对调用它的线程的引用。一旦得到对主线程的引用,就可以像
控制其他线程那样控制主线程了。
PS:主线程的优先级默认值:5,线程组:java.lang.ThreadGroup[name=main,maxpri=10]


3 创建线程
最通常情况下,通过实例化Thread类型的对象创建线程。
创建线程的 两种方法:
·实现Runnable接口
·扩展Thread类本身


3.1 实现Runnable接口(方式一)
    run方法和main线程的唯一区别:run()方法为程序中另外一个并发线程的执行建立了入口点。
当run()方法返回时,这个线程将结束。
    在创建实现了Runnable接口的类之后,可以在类中实例化Thread类型的对象。
Thread的构造函数之一:Thread(Runnable threadOb,String threadName)
    其中threadOb是实现了Runnable接口的类的实例,这定义了从何处开始执行线程。
新线程的名字由threadName指定。
    在创建了新线程之后,只有调用线程的start()方法,线程才会运行,该方法是在Thread
类中声明的。本质上,start()方法执行对run()方法的调用。
3.2 扩展Thread类(方式二)
    创建一个扩展了Thread的新类,然后创建该类的实例。扩展类必须重写run()方法,run()方法
是新线程的入口点。扩展类还必须调用start()方法以开始新线程的执行。


4.创建多个线程


5.使用isAlive()和join()方法
有两种方法可以确定线程是否已经结束。首先,可以为线程调用isAlive()方法。该方法由Thread类定义。
final boolean isAlive()
如果线程仍然在运行,isAlive()方法就返回true,否则返回false.
·join()方法用来等待线程结束,如下所示:
final void join() throws InterruptedException
该方法会一直等待,直到调用线程终止。
命名原因:调用线程一直等待,直到指定的线程加入(join)其中为止。
join()方法的另外一种形式,允许指定希望等待指定线程终止的最长时间。


6.线程优先级
设置线程优先级,使用setPriority()方法,它是Thread类的成员。该方法的
一般形式: final void setPriority(int level).
其中level是优先级,取值在MIN_PRIORITY和MAX_PRIORITY之间。目前1<=level<=10.默认优先级NORM_PRIORITY是5.
这些优先级在Thread类中作为static final变量定义。
final int getPriority()//获取当前设置的优先级。
警告:不同的Java实现对于任务调度可能有很大的区别。如果线程依赖于抢占式行为,而不是协作性地放弃CPU,
那么经常会引起不一致性。使用Java实现可预测、跨平台行为地最安全方法是使用自愿放弃CPU控制权地线程。


7.同步
同步地关键是监视器的概念,监视器是用作互斥锁的对象。在给定时刻,只有一个线程可以拥有监视器。
当线程取得锁时,也就是进入了监视器。其他所有企图进入加锁监视器的线程都会被挂起,直到第一个线程推出监视器。
也就是说,这些等待的其他线程在等待监视器。如果需要的话,拥有监视器的线程可以再次进入监视器。


同步代码的方法(使用synchronized,两种)


7.1使用同步方法
Java中,所有对象都有与他们自身关联的隐式监视器。
为了进入对象的监视器,只需要调用使用synchronized关键字修饰过的方法。
当某个线程进入同步方法中时,条用同一实例的该同步方法(或其他同步方法)的所有其他线程都必须等待。
为了推出监视器并将对象的控制权交给下一个等待线程,监视器的拥有者只需要简单地从同步方法返回。


记住!!!:一旦线程进入一个实例地同步方法,所有其他线程就都不能再进入相同实例地任何同步方法。但是,
仍然可以继续调用同一实例地非同步部分。


7.2 synchronized语句
将类定义的方法的调用放到synchronized代码块中。一般形式如下:
synchronized(objRef){
//statements to be synchronized
}
其中,objRef是对被同步对象的引用。synchronized代码块确保对objRef对象的成员方法的调用,只会在
当前线程成功进入objRef的监视器之后发生。


8 线程间通信
Java通过wait()、notify()以及notifyAll()方法,提供了一种巧妙的线程间通信机制,
这些方法再Object中是作为final方法实现的,因此所有类都有这些方法。所有这3个
方法都只能在同步上下文中调用。
·wait()方法通知调用线程放弃监视并进入休眠,直到其他一些线程进入同一个监视器并调用notify()方法或nitifyAll()方法。
·notify()方法唤醒调用相同对象的wait()的线程。
·notifyAll()方法唤醒调用相同对象的wait()方法的所有线程,其中的一个线程将得到访问权。
这3个方法都是在Object类中定义的:
final void wait() throws InterruptedException
final void notify()
final void notifyAll()
wait()方法还有另外一种形式,允许指定等待的时间间隔。
    在通过例子演示线程间通信之前,还有重要的一点需要指出。尽管在正常情况下,wait()方法会等待直到调用notify()或notifyAll()方法,
但是还有一种几率很小确很可能会发生的情况,等待线程由于假唤醒(spurious wakeup)而被唤醒。对于这种情况,等待线程也会被唤醒,然而
却没有调用notify()或notifyAll()方法(本质上,线程在没有什么明显理由的情况下就被恢复了)。由于存在这种极小的可能,Oracle推荐应当
在一个检查线程等待条件的循环中调用wait()方法。


死锁


9 挂起、恢复、停止线程
10 获取线程的状态
Thread.State getState()
该方法返回Thread.State类型的值。State是由Thread类定义的枚举类型
getState()方法的返回值
BLOCKED:线程因为正在等待需要的锁而挂起执行
NEW:线程还没有开始运行
RUNNABLE:线程要么当前正在执行,要么在获得CPU的访问权之后执行
TERMINATED:线程已经完成执行
TIMED_WAITING:线程挂起执行一段指定的时间,例如当调用sleep()方法的时候就会处于这种状态。当调用wait()或join()方法的
暂停版时,也会进入这种状态
WAITING:线程因为等待某些动作而挂起执行。例如,因为调用非暂停版的wait()或join()方法而等待时,会处于这种状态。


11 使用多线程
有效利用Java多线程特性的关键时并发地而不是顺序地思考问题
Fork/Join框架
原创粉丝点击