Thread和Runnable
// Thread
public class MyThread extends Thread {
public void run(){
System.out.println("MyThread running");
}
}
MyThread myThread = new MyThread();
// 线程启动后start方法立即返回,不会等待到run方法执行完毕
myTread.start();
// 匿名内部类
Thread thread = new Thread() {
public void run(){
System.out.println("Thread Running");
}
};
thread.start();
// run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
// Runnable
public class MyRunnable implements Runnable {
public void run(){
System.out.println("MyRunnable running");
}
}
Thread thread = new Thread(new MyRunnable());
thread.start();
// 匿名内部类
Runnable myRunnable = new Runnable() {
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();
死锁举例
public class DeadLock {
private static String obj1 = "obj1";
private static String obj2 = "obj2";
public static void main(String[] args){
Thread a = new Thread(new T1());
Thread b = new Thread(new T2());
a.start();
b.start();
}
}
class T1 implements Runnable{
@Override
public void run(){
try{
System.out.println("T1 running");
while(true){
synchronized(DeadLock.obj1){
System.out.println("T1 get obj1");
Thread.sleep(3000);
synchronized(DeadLock.obj2){
System.out.println("T1 get obj2");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
class T2 implements Runnable{
@Override
public void run(){
try{
System.out.println("T2 running");
while(true){
synchronized(DeadLock.obj2){
System.out.println("T2 get obj2");
Thread.sleep(3000);
synchronized(DeadLock.obj1){
System.out.println("T2 get obj1");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
CAS
- CAS的底层原理:借助C调用CPU指令,lock + cmpxchg
- ABA问题
- 线程1在进if前,CPU时间被线程2抢走
- 线程2将current值改成别的,又改回来
- 线程1进if时,对线程2做的事情无感知
- 问题案例
- 单链表实现堆栈
- 线程1看见:A -> B,想将A替换成B,head.compareAndSet(A, B);
- 线程2迅速将A,B pop,然后push D,C,A
- 线程1执行CAS,将A换成B
- 那么,本该是A -> C -> D的链表,此时就变成了B
- 解决方案:AtomicStampedReference/AtomicMarkableReference
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
偏向锁
Thread.sleep
yield & join
- 共性
- 当前持锁线程执行,对当前线程生效
- yield:无InterruptedException
- 交出cpu,不释放锁
- 从运行状态转化为可运行状态(无法保证迅速切换,和线程调度实现相关)
// Thread
public static native void yield();
- sleep:有InterruptedException
- 交出cpu,不释放锁
// Thread
public static void sleep(long millis, int nanos) // 这个nanos其实不提高精度,只是在过半(含半)或者millis为0时,使millis+1
public static native void sleep(long millis) throws InterruptedException;
join:有InterruptedException
// Thread
public final void join() throws InterruptedException // join(0)
public final synchronized void join(long millis) throws InterruptedException
- 假设在main中,执行了t1.join(),那么main会等待t1跑完再往下走,但是和t2、tn没什么关系,也就是说影响的仅仅是main(调用join的那个线程)而已
- 本质是调用wait,wait在该线程对象上;那么,谁去唤醒它?
- t1是个线程,join方法又是synchronized的,因此main其实是wait在了t1这个线程上;t1这种线程锁有点特殊,当run方法被跑完时,Thread subsystem会执行t1.notifyAll
//一个c++函数:
void JavaThread::exit(bool destroy_vm, ExitType exit_type);
//这家伙是啥,就是一个线程执行完毕之后,jvm会做的事,清理收尾工作,
//里面有行贼不起眼的代码:
ensure_join(this);
//代码如下:
static void ensure_join(JavaThread* thread) {
Handle threadObj(thread, thread->threadObj());
ObjectLocker lock(threadObj, thread);
thread->clear_pending_exception();
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
java_lang_Thread::set_thread(threadObj(), NULL);
//see here
lock.notify_all(thread);
thread->clear_pending_exception();
}
wait和notify
- wait
// Object
public final void wait() throws InterruptedException // wait(0)
public final void wait(long timeout, int nanos) throws InterruptedException // nanos同sleep
public final native void wait(long timeout) throws InterruptedException
- notify
// Object
public final native void notify(); // 随机唤醒
- notifyAll
// Object
public final native void notifyAll(); //唤醒全部
interrupt
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel </code>interruptible
* channel<code>} then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
- 线程中断
- public void Thread.interrupt() // 中断线程
- public boolean Thread.isInterrupted() // 判断是否被中断
- public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态
- 什么是线程中断?
- 如果不了解Java的中断机制,这样的一种解释极容易造成误解,认为调用了线程的interrupt方法就一定会中断线程
- 其实,Java的中断是一种协作机制。也就是说调用线程对象的interrupt方法并不一定就中断了正在运行的线程,它只是要求线程自己在合适的时机中断自己
- 每个线程都有一个boolean的中断状态(不一定就是对象的属性,事实上,该状态也确实不是Thread的字段),interrupt方法仅仅只是将该状态置为true
- 对于非阻塞中的线程, 只是改变了中断状态, 即Thread.isInterrupted()将返回true,并不会使线程停止
// 这样中断,是不会有效果的,只是更改了中断状态位
public void run() {
while(true) {
Thread.yield();
}
}
t1.interrupt();
// 优雅终止
public void run() {
while(true) {
if(Thread.currentThread().isInterrupted()) {
System.out.println("Interruted!");
break;
}
Thread.yield();
}
}
- 对于可取消的阻塞中线程, 比如Thread.sleep(), Object.wait(), Thread.join();线程收到中断信号后, 会抛出InterruptedException, 同时把中断状态置回false
// 取消阻塞中的线程
public void run() {
while(true) {
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interruted When Sleep");
//设置中断状态,因为异常抛异常时中断标记位已被清除
Thread.currentThread().interrupt();
}
Thread.yield();
}
}
suspend & resume
- Deprecated,不推荐使用
- 原因
- suspend不释放锁,在无法控制线程运行的先后顺序下,如果某线程的resume方法先被运行,那之后运行的suspend,将一直占有这把锁,造成死锁发生
// 场景模拟
public class Test{
static Object u = new Object();
static TestSuspendThread t1 = new TestSuspendThread("t1");
static TestSuspendThread t2 = new TestSuspendThread("t2");
public static class TestSuspendThread extends Thread {
public TestSuspendThread(String name) {
setName(name);
}
@Override
public void run() {
synchronized (u) {
System.out.println("in " + getName());
Thread.currentThread().suspend();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
t1.resume();
t2.resume(); //t2的resume先于suspend执行,所以suspend就让t2死在那里了
t1.join();
t2.join();
}
}
网友评论