美文网首页
java多线程-2-Thread相关

java多线程-2-Thread相关

作者: 宠辱不惊的咸鱼 | 来源:发表于2019-09-30 08:59 被阅读0次

    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();
        }
    }
    

    相关文章

      网友评论

          本文标题:java多线程-2-Thread相关

          本文链接:https://www.haomeiwen.com/subject/furcpctx.html