常见误解情况:
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:
interrupt
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
- 如果当前线程无法修改该线程
-
interrupted
public static boolean interrupted ()
-
测试当前线程是否已经中断。线程的
中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
-
-
返回:
-
如果当前线程已经中断,则返回
true
;否则返回false
。
另请参见:
-
isInterrupted()
-
如果当前线程已经中断,则返回
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