常见误解情况:
Thread.yield(): 放弃当前的cpu时间片,进入ready to run状态. 错
Thread.yield():建议放弃当前cpu时间片,但是否放弃由jvm决定。
Java 5新特性:
ExecutorService exec = Executors.newCachedThreadPool(); exec.execute( new MyThread1();); exec.execute(new MyThread2()); exec.shutdown();
Executors.newCachedThreadPool(); Executors.newFixedThreadPool(5); Executors.newSingleThreadExecutor();// 等于Executors.newFixedThreadPool(1);
java 不建议直接使用线程,而是添加了executors类,我们使用的时候只需要将需要做的事情放入exec.execute()中,设定执行的线程数,其余的事情由java调度。
Executors.newSingleThreadExecutor():一个线程顺序执行放入的任务。
execute.submit(Callable )返回Future类,可以异步的查看线程运行状况已经运行结果。
Lock lock = new ReentrantLock(); lock.lock(); try{ code block; }finally{ lock.unlock(); }
可以显式的调用lock实现线程工作。
锁:
对象锁:每个对象上都有一把锁,但一个线程获得这个对象锁后,其他线程将被阻塞,直到获得对象锁的线程释放该锁。
1. 当synchronized直接修饰方法时,进入该方法的线程获得的是该方法对应实例的对象锁。
2. 当synchronized直接修饰代码块的时候,synchronized(**){code block}, 线程获得的是对象**的锁。
类锁:当synchronized修饰静态方法的时候,静态方法获得的是类锁。
1. public static synchronized void instance(){code block}, 调用该方法的线程获得的是该方法从属的类的锁。
(底层实现: 对象锁计数器初始化为0,当获得对象锁的对象多次获得对象锁的同时,对象锁计数器会累加。当计数器为0的时候,其他线程才能获得对象锁。)
多线程协作:
wait()和notify()用来是当前线程挂起或者唤醒。
他们作为Object基类的一部分是因为他们都是操作锁的,锁是所有对象的一部分而非Thread特有。
wait()的含义:我已经做完线程该做的事情,且等待其他线程或者资源。所以释放对象锁,等待再次被唤醒。
wait()可以防止线程忙等待。
若wait()的使用没有获得锁则抛出IllegalMonitorStateException 。
wait()使用必须获得锁,且notify()使用也必须获得锁,且notify()唤醒的是notify()所获得锁所对应的wait()方法。
class MyThread1 implements Runnable { public boolean flag = true; Object syncObject = new Object(); @Override public void run() { synchronized (syncObject ) { System.out.println("Entry thread 1"); while (flag) { System.out.println("thread 1 wait"); try { syncObject.wait(); } catch (InterruptedException e1) { e1.printStackTrace(); } } System.out.println("Out of thread 1"); } } } class MyThread2 implements Runnable { Runnable runnable; public MyThread2(Runnable runnable) { this.runnable = runnable; } @Override public synchronized void run() { System.out.println("Entry thread 2"); int i = 0; while (((MyThread1)runnable).flag) { synchronized (((MyThread1)runnable).syncObject ) { i++; if (i == 5) { ((MyThread1)runnable).flag = false; } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } ((MyThread1)runnable).syncObject.notifyAll(); System.out.println("thread 2 notify."); } } System.out.println("Out of thread 2"); } } public class WaitAndNotify { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); Runnable a = new MyThread1(); exec.execute(a); exec.execute(new MyThread2(a)); exec.shutdown(); } }
以上例子,wait和notify获得的都是syncObject的锁,若在synchronized方法中直接使用wait那么wait获得的锁是当前对象的锁。那么notify也必须获得与wait对应一样的锁才能唤醒wait的线程。
wait(Time)和sleep(Time)的区别:都表示等待Time时间后继续运行,但是wait()会释放锁,sleep不会释放锁。当没有获得锁的情况中只能使用sleep().
中断 :
t.interrupt(),t.isInterrupted(),Thread.interrupted()
t.interrupt():会设置这个线程的中断状态为true 。且对于如果一个线程已经被阻塞或者试图执行一个阻塞操作,那么这个线程会抛出InterruptedException ,对于sleep和wait方法都会默认捕捉InterruptedException方法。
当调用t.interrupt()后再调用t.isInterrupted()线程true。
当有别的线程调用了本线程的interrupt( )时,会设置一个标记以表示这个这个线程被打断了。当本线程捕获这个异常的时候,会清除这个标志。所以catch语句会永远报告说isInterrupted( )是false。这个标记是用来应付其它情况的,或许在没出异常的情况下,线程要用它来检查自己是不是被中断了。
Thread.interrupted()调用过后会清除了其中断状态.
官方API:
public void interrupt ()
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess
方法就会被调用,这可能抛出 SecurityException
。
如果线程在调用 Object
类的 wait()
、wait(long)
或 wait(long, int)
方法,或者该类的 join()
、join(long)
、join(long, int)
、sleep(long)
或 sleep(long, int)
方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException
。
如果该线程在可 中断的通道 上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException
。
如果该线程在一个 Selector
中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup
方法一样。
如果以前的条件都没有保存,则该线程的中断状态将被设置。
SecurityException
- 如果当前线程无法修改该线程
public static boolean interrupted ()
true
;否则返回
false
。
isInterrupted()
public boolean isInterrupted ()
true
;否则返回
false
。
interrupted()
t.interrupt()不会中断正在执行的线程,只是将线程的标志位设置成true。但是如果线程在调用sleep(),join(),wait() 方法时线程被中断,则这些方法会抛出InterruptedException,在catch块中捕获到这个异常时,线程的中断标志位已经被设置成 false了,因此在此catch块中调用t.isInterrupted(),Thread.interrupted()始终都为false,
而t.isInterrupted与Thread.interrupted()的区别是API中已经说明很明显 了,Thread.interrupted()假如当前的中断标志为true,则调完后会将中断标志位设置成false