suspend()和resume()和stop方法,是一个线程操作另一个线程。 如果对方线程持有锁进入挂起状态,而本线程又去请求锁,没有其他线程去resume那个线程,就成死锁状态了。 这三个方法是弃用的方法,可以用wait和notify代替。但是,需要修改对方线程的代码,使用wait和notify。
sleep是该线程自己睡觉,不影响别人。 ------------------------------------------------------ 线程的run()方法完成后,线程就终结了。但是线程对象还是可以访问的,除非它被回收了。 通常不应该持有线程对象的引用,持有的情况,通常是为了判断线程是否完成。 这个可以用join()方法代替。 如果目标线程执行完毕,则join()方法立即返回。 如果没有,则会阻塞,直到执行完毕。 ------------------------------------------------------ 停止线程的办法: (1)设置Flag private volatile boolean done = false; //注意使用volatile public void run( ) { while (!done) { ... } } public void setDone( ) { done = true; } 如果while中阻塞了,就没办法。
(2)中断线程 public void run( ) { while (!isInterrupted( )) { ... } } 其它线程中:xx.interrupt();
如果中间正在执行sleep,那么sleep马上结束,抛出InterruptedException, 但是,isInterrupted()还是false。记住!!
如果正在执行一般代码,则isInterrupted()是true。
好处: 如果目标线程在执行sleep,wait,join,阻塞读取等阻塞动作时, 该动作可以直接被中断,抛出InterruptedException。
当然,如果后面又sleep了,就又睡着了。除非再interrupt一次。 --------------------------------------------------- 判断当前线程 Thread.currentThread(),返回线程对象。
if (Thread.currentThread() != this)
while (!Thread.currentThread( ).isInterrupted( )) { --------------------------------------------------- java基本变量的存取是原子性的,除了long和doule。
volatile变量的读写都在主内存中进行,其它线程可见。 否则,线程可能复制缓存到自己的内存中。
如果数组声明为volatile,只是数组引用本身是volatile的,元素不是。 多个线程操作数组,只能同步。或使用原子变量。
volatile只适合一句话的,变量读写的语句。 --------------------------------------------------- 显式LOCK 5.0提供了LOCK接口,显式的LOCK和unlock。 private Lock scoreLock = new ReentrantLock(); //可重入锁 try { scoreLock.lock( ); } finally { scoreLock.unlock( ); } 多个对象可以共享同一个锁,一个对象也可以有多个锁了。
用synchronized还是显式Lock,看个人爱好。不过,随着程序变复杂,使用synchronized会比较困难。 synchronized时,出了方法就释放锁,即使是出了异常。
Lock接口: tryLock(),尝试加锁,返回true或false。不等待。 --------------------------------------------------- 加锁后,当前线程执行要锁的方法时,直接进入,无需等待锁,因为它已经有锁了。
ReentrantLock类也有此功能,但不是所有实现Lock接口的类都这样。 ----------------------------------------------------- wait和notify,需要在同步块中执行。否则可能不起作用。 wait的时候,进入等待状态,释放锁。sleep则不会自动释放锁。 直到notify它,再去取得锁。
一个线程通知另一个。
wait之前应该测试一下条件,需要等待的话就wait, 被唤醒后,仍然要测试一下条件,再决定是否wait。有可能不需要wait了,有可能需要。 在收到notify通知,和醒来之间,可能其它线程又改变了条件。
如果线程被中断,wait方法会提前结束。
如果可能有多个线程在wait,就用notifyAll()。 所有线程得到通知,还得抢锁。 ----------------------------------------------------------- public void useFoo( ) { if (foo == null) { synchronized(this) { if (foo == null) foo = new Foo( ); } } foo.invoke( ); } 双重检查是不成立的,new Foo()执行完之前,中途foo可能就已经不是null了, 另外一个线程就直接执行foo.invoke了。构造方法不是一个原子操作。 ----------------------------------------------------------- AtomicInteger, AtomicLong, AtomicBoolean,AtomicReference 本身能保证原子操作,不需要同步。 但是,类似同时更新两个AtomicInteger 这样的操作,仍然要同步。把多步操作变成一步。
AtomicIntegerArray, AtomicLongArray, and AtomicReferenceArray,没有boolean的数组 一次只能操作一个元素。
AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, 和 AtomicReferenceFieldUpdater
AtomicMarkableReference 和 AtomicStampedReference
用起来也挺费劲的呀。 ----------------------------------------------------------- 线程本地变量 每个线程都持有一个副本,各自操作自己的,互不影响。 private static ThreadLocal<HashMap> results = new ThreadLocal<HashMap>( ) { protected HashMap initialValue( ) { return new HashMap( ); } }; HashMap hm = results.get( ); ....貌似性能比较差劲。 ----------------------------------------------------------- yield(),通知系统选择别的线程执行,让出。对系统依赖性大,不是那么绝对。 ------------------------------------------------------------ green thread模式,java虚拟机管理线程,操作系统完全不知道这些线程的存在。 也称为用户级线程,由用户Application管理,不调用操作系统。
Windows Native Threads,Java的线程与操作系统的线程是一一对应的。 ------------------------------------------------------------ 变量只是一个引用,实际使用的是指向对象的锁。 synchronized时等待的是哪个锁,轮到自己时就用哪个锁,即使此时这个变量的引用已经改变。 ------------------------------------------------------------ static boolean interrupted() 测试当前线程是否已经中断。 boolean isInterrupted() 测试线程是否已经中断。 ------------------------------------------------------------ stop 的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。 目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。 如果目标线程等待很长时间(例如基于一个条件变量),则应使用 interrupt 方法来中断该等待。 ------------------------------------------------------------ 不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?。 ------------------------------------------------------------ 今天用了一个线程,跑第一遍的时候没有问题,跑第二遍的时候报了错:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalThreadStateException at java.lang.Thread.start(Unknown Source)
后来经过一位同事的提醒才明白一个线程跑过后是不能再次被start的,得再次new出一个线程才行!
---------------------------------------------------------------
|