初涉多线程

来源:互联网 发布:中国根域名服务器 镜像 编辑:程序博客网 时间:2024/05/02 04:24

1.     什么是线程

直接调用run()方法,不会建立新线程,只有调用start()方法才能开启新线程.

当前线程调用sleep()wait()方法,让线程处以空闲状态.给其他线程机会完成它们的运行,但大部分操作系统都有自己调度线程的方法.即使两个利己线程,都有机会得到CPU的资源.

如果一个类需要新线程运行,那它可以继承Thread,并覆盖run()方法.如果该类已有超类.那么可以实现Runnable接口.如果线程的run()方法需要专门访问一个类,那更好的方法是使用内部类.

2.     线程的中断

interrupted() 静态方法 返回线程的中断状态,并将中断状态设为false

isInterrupte() 实例方法 仅返回线程的中断状态

interrupte() 将线程的中断状态设为true 仅改变线程interrupt标志

单一个线程处以sleep()wait()方法时,被其他线程调用了该线程的interrupt 方法.这两个方法会抛出InterruptedException 异常.通过捕获这个异常可以结束线程的运行.如果仅对sleep()wait()方法进行捕获.线程还可以继续运行.同时interrupt又被设置为false

即使调用t.interrupte().线程仍继续运行.并且输入恒为false

3.     线程的属性

线程有4种状态

new()

但调用new 运算符创建一个线程时,该线程尚未运行.这时线程便处以new 状态

runnable(可运行)

当调用start方法时,线程便处于可运行状态.可运行并不是说正在运行.需要操作系统为该线程赋予运行的时间

一些操作系统(windows)能够为每个可运行的线程赋予一个时间片,以便执行它的任务.当该时间片用完时,操作系统便为另一个线程提供运行的机会.这种方法称为时间分片(time slicing)

blocked(被中断运行)

当出现下列操作,线程便进入中断状态

调用了该线程的sleep()方法

该线程调用了一个I/O时中断的操作.

该线程调用了wait()方法;

该线程试图锁定一个被另一个线程锁定的对象

调用了该线程的suspend()方法,该方法已作废.

相应的退出中断状态

线程的睡眠经过了规定的毫秒数

I/O操作完成

调用wait()方法等待的线程.其他线程调用了notify()notifyAll()方法

线程等待锁时,另一个线程放弃了该锁

如果调用了该线程的suspend()方法,那调用该线程的resume()方法就退出中断.同样已废

dead()

run方法自然退出,此时线程自然死亡

由于异常未捕获而导致run方法终止,会导致线程突然死亡

调用stop()方法可杀死线程.该方法以作废

 

java守护线程:

一种特殊的线程,从属于创建它的线程.主要应用于程序的非核心处理部分.比如word文档中用来监听输入的是非守护线程.用来检查拼写的是可以守护线程.

        

如果上面的线程是非守护线程的活.jvm需要等到 线程死亡才 结束运行,如果是守护线程则直接结束运行

 

做游戏中的背景音乐可以考虑用守护线程来做.

线程组

是一种树结构

 

4.     线程的优先级

java,每个线程都有一个优先级.优先级的取值可以为1(MIN_PRIORITY)~10 (MAX_PRIORITY).在默认情况下,一个线程将继承其父线程的优先级

当线程调度程序有机会选择一个新线程时,它通常会选择当前处于可运行状态下的高优先级线程.如果有多个高优先级线程.无法控制调度程序去选定一个特定的线程.一般调度程序会随机选择一个线程.

yield()静态方法 使当前线程放弃运行.如果有其他可运行线程的优先级至少与当前线程相同.那么它们将被安排在下次运行

5.     利己线程

当某个线程执行一个很长的循环时,它应该始终调用sleep()yield()方法.以确保它不会独占整个系统.不遵循这个原则的线程称为利己线程

如果程序在windows或者在本机线程机制下运行,那么利己线程不会独占整个系统

6.     同步

假设有两条线程,同时执行value+=random;在两条线程中value是内存中的同一位置,比如.既是同一对象的同一属性.random是不同的随机值.线程执行的操作是 value装入寄存器.并将random相加.再将结果重新移到value.

如果此时value=1000,线程一的random=200,线程2random=300;当线程1执行了将1000装入寄存器.并将random相加.此时线程1中的寄存器的值为1200.系统到这时刚好把线程1的运行中断了.并唤醒了线程2. 线程21000装入寄存器.并将random相加.此时线程2中的寄存器的值为1300,并将结果赋给了value.接着线程1被唤醒了.它执行了将寄存器中的值1200赋给了value的操作.该操作破坏了线程2进行的修改.程序运行的正确性就被破坏了.

每个线程可以同时对同一个对象的属性进行修改.就破坏了类的完整性.这就是异步的危险.

synchronized

当一个线程调用了synchronized方法时.synchronized方法结束之前.其他线程再也无法执行同一对象中的synchronized方法.

对象锁

实际上当线程调用了sychronized方法是.便将对象转为锁定状态.处于锁定状态的对象.其他线程只能访问该对象的unsynchronized方法.若调用了synchronized方法.就等待该对象的锁被打开.当线程退出了它的synchronized方法时,便打开了对象的锁

waitnotify

waitnotify notifyAll 都是Object类的方法.

当调用wait方法是对象便打开自己的锁.并且中断当前线程的运行.当前线程进入等待列表

notify:从对象的等待列表中删除一个任意选择的线程

notifyAll:将对象等待列表中的所有线程全部删除.

从等待列表删除线程.并不会立刻激活该线程.只能撤销等待线程的中断状态.与其他线程展开竞争

同步块

同步静态方法

如果一个线程调用了一个类的静态synchronized方法,那么这个类其他的静态synchronized方法都会被锁定.直到静态synchronized方法返回.

 

7.     死锁

如果其他所有线程都被wait()锁定,并且最后一个活动线程在不打开其他线程的锁的情况下,调用wait(),这种情况叫做死锁.

废除stopsuspend方法

stop()不会使对象永久性锁定,但会使对象受损.(方法执行不完整)

当一个线程拥有对象锁时,被调用suspend不会解除锁.那其他挂起的线程要等待该对象撤销锁定.便形成了死锁.

超时

wait(long millis) wait(long millis,int nanos)

如果线程调用以上方法进行等待.那么在规定时间到后,线程还没被notifyAll/notify唤醒时,线程将自动唤醒.