高并发

Doug Lea 并发大师

学习方法:

场景-需求-解决方案-应用-原理

 

进程的生命周期:创建-销毁

 

Java中如何运用线程:

1,Runnable接口

2,Thread类(本质上是实现了Runnable接口)--使用较少,对资源不可控

3,ThreadPool线程池   --实际运动较多,风险(如 死锁,上下文切换等)

4,Callable/Future 带返回值的

线程可以合理利用多核心CPU资源,提高程序的吞吐量。--单核心行不行?

实际运用:责任链【略】

线程的生命周期:6种状态

public class Thread implements Runnable {
    //...
    public static enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
        private State() {
        }
    }
    //...
}

示意图

 

下面用代码演示一下线程的一些状态:waiting,timed_waiting,blocked

package com.gupaoedu.vip.pattern.mysingleton.hungry;
import java.util.concurrent.TimeUnit;
/**
 * Created by huhuba on 2019/11/30.
 */
public class Test {

    public static void main(String[] args) {
        //线程状态转化演示
        //1,RUNNING==>Time_Waiting
        new Thread(()->{
            while (true) {
                try {
                    //相当于Thread.sleep(100*1000);
                    TimeUnit.SECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Time_Waiting_Thread").start();
        //2,RUNNING==>Waiting
        new Thread(()->{
            while(true){
                synchronized (Test.class){
                    try {
                        Test.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"Waiting_Thread").start();

        //3,RUNNING==>BLOCKED
        new Thread(new BlockedDemo(),"block_01_thread").start();
        new Thread(new BlockedDemo(),"block_02_thread").start();
    }


    static class BlockedDemo extends Thread{
        @Override
        public void run() {
            while(true){
                synchronized (BlockedDemo.class){
                    try {
                        TimeUnit.SECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

执行上述代码后,打开终端,在该class文件所在目录执行 jps

E:\cms\code\huangxj\gupaoedu-vip-pattern-singleton\target\classes\com\gupaoedu\vip\pattern\mysingleton\hungry>jps
288 Test
6676 Launcher
4200 RemoteMavenServer
5784 Jps
8252

其中,288是目标进程号:

执行 jstack 288
得到当前3个线程各自的状态


"block_02_thread" #16 prio=5 os_prio=0 tid=0x0000000019362000 nid=0x19f0 waiting for monitor entry [0x0000000019f6f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.gupaoedu.vip.pattern.mysingleton.hungry.Test$BlockedDemo.run(Test.java:45)
        - waiting to lock <0x00000000d5ed0658> (a java.lang.Class for com.gupaoedu.vip.pattern.mysingleton.hungry.Test$BlockedDemo)
        at java.lang.Thread.run(Thread.java:748)

"block_01_thread" #14 prio=5 os_prio=0 tid=0x0000000019361800 nid=0x2e14 waiting on condition [0x0000000019e6e000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at com.gupaoedu.vip.pattern.mysingleton.hungry.Test$BlockedDemo.run(Test.java:45)
        - locked <0x00000000d5ed0658> (a java.lang.Class for com.gupaoedu.vip.pattern.mysingleton.hungry.Test$BlockedDemo)
        at java.lang.Thread.run(Thread.java:748)

"Waiting_Thread" #12 prio=5 os_prio=0 tid=0x000000001935e800 nid=0x2b90 in Object.wait() [0x0000000019d6f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000d5ba5d48> (a java.lang.Class for com.gupaoedu.vip.pattern.mysingleton.hungry.Test)
        at java.lang.Object.wait(Object.java:502)
        at com.gupaoedu.vip.pattern.mysingleton.hungry.Test.lambda$main$1(Test.java:26)
        - locked <0x00000000d5ba5d48> (a java.lang.Class for com.gupaoedu.vip.pattern.mysingleton.hungry.Test)
        at com.gupaoedu.vip.pattern.mysingleton.hungry.Test$$Lambda$2/1831932724.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)


"Time_Waiting_Thread" #11 prio=5 os_prio=0 tid=0x000000001935a800 nid=0x1568 waiting on condition [0x0000000019c6f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at com.gupaoedu.vip.pattern.mysingleton.hungry.Test.lambda$main$0(Test.java:15)
        at com.gupaoedu.vip.pattern.mysingleton.hungry.Test$$Lambda$1/990368553.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

 

Thread.

习题:

1,线程的启动为什么是start?

实际上在OS层面创建一个java线程,并设置为RUNNABLE状态,在合适的时候来回调run方法

如果直接调用run方法,那就是调用了这个类的方法,并不会创建一个线程。

查看源码:start()--private native void start0();

--start0()源码查找:

1,下载hotspot源码/openjdk源码

2,根据JVM引导 http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c

中的42行找到一些native方法,其中就包含start0


static JNINativeMethod methods[] = {
    {"start0",           "()V",        (void *)&JVM_StartThread},
    {"stop0",            "(" OBJ ")V", (void *)&JVM_StopThread},
    {"isAlive",          "()Z",        (void *)&JVM_IsThreadAlive},
    {"suspend0",         "()V",        (void *)&JVM_SuspendThread},
    {"resume0",          "()V",        (void *)&JVM_ResumeThread},
    {"setPriority0",     "(I)V",       (void *)&JVM_SetThreadPriority},
    {"yield",            "()V",        (void *)&JVM_Yield},
    {"sleep",            "(J)V",       (void *)&JVM_Sleep},
    {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},
    {"countStackFrames", "()I",        (void *)&JVM_CountStackFrames},
    {"interrupt0",       "()V",        (void *)&JVM_Interrupt},
    {"isInterrupted",    "(Z)Z",       (void *)&JVM_IsInterrupted},
    {"holdsLock",        "(" OBJ ")Z", (void *)&JVM_HoldsLock},
    {"getThreads",        "()[" THD,   (void *)&JVM_GetAllThreads},
    {"dumpThreads",      "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
};

根据 JVM_StartThread,在hotspot文档中找到jvm.cpp文件

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;

  // We cannot hold the Threads_lock when we throw an exception,
  // due to rank ordering issues. Example:  we might need to grab the
  // Heap_lock while we construct the exception.
  bool throw_illegal_thread_state = false;

  // We must release the Threads_lock before we can post a jvmti event
  // in Thread::start.
  {
    // Ensure that the C++ Thread and OSThread structures aren't freed before
    // we operate.
    MutexLocker mu(Threads_lock);

    // Since JDK 5 the java.lang.Thread threadStatus is used to prevent
    // re-starting an already started thread, so we should usually find
    // that the JavaThread is null. However for a JNI attached thread
    // there is a small window between the Thread object being created
    // (with its JavaThread set) and the update to its threadStatus, so we
    // have to check for this
    if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
      throw_illegal_thread_state = true;
    } else {
      // We could also check the stillborn flag to see if this thread was already stopped, but
      // for historical reasons we let the thread detect that itself when it starts running

      jlong size =
             java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
      // Allocate the C++ Thread structure and create the native thread.  The
      // stack size retrieved from java is signed, but the constructor takes
      // size_t (an unsigned type), so avoid passing negative values which would
      // result in really large stacks.
      size_t sz = size > 0 ? (size_t) size : 0;
      native_thread = new JavaThread(&thread_entry, sz);

      // At this point it may be possible that no osthread was created for the
      // JavaThread due to lack of memory. Check for this situation and throw
      // an exception if necessary. Eventually we may want to change this so
      // that we only grab the lock if the thread was created successfully -
      // then we can also do this check and throw the exception in the
      // JavaThread constructor.
      if (native_thread->osthread() != NULL) {
        // Note: the current thread is not being used within "prepare".
        native_thread->prepare(jthread);
      }
    }
  }

  if (throw_illegal_thread_state) {
    THROW(vmSymbols::java_lang_IllegalThreadStateException());
  }

  assert(native_thread != NULL, "Starting null thread?");

  if (native_thread->osthread() == NULL) {
    // No one should hold a reference to the 'native_thread'.
    delete native_thread;
    if (JvmtiExport::should_post_resource_exhausted()) {
      JvmtiExport::post_resource_exhausted(
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
        "unable to create new native thread");
    }
    THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
              "unable to create new native thread");
  }

  Thread::start(native_thread);

 Thread::start(native_thread)这个方法在 Thread.cpp文件中

void Thread::start(Thread* thread) {
  trace("start", thread);
  // Start is different from resume in that its safety is guaranteed by context or
  // being called from a Java method synchronized on the Thread object.
  if (!DisableStartThread) {
    if (thread->is_Java_thread()) {
      // Initialize the thread state to RUNNABLE before starting this thread.
      // Can not set it after the thread started because we do not know the
      // exact thread state at that time. It could be in MONITOR_WAIT or
      // in SLEEPING or some other state.
      java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
                                          java_lang_Thread::RUNNABLE);
    }
    os::start_thread(thread);//操作系统的线程
  }
}

2,线程的终止

Thread.interrupt()

import java.util.concurrent.TimeUnit;
/**
 * Created by huhuba on 2019/11/30.
 */
public class Test {
    static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                i++;
            }
            System.out.println("i:"+i);
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();//如果没有该步骤,线程将永远在while中死循环
    }
}

 

不建议使用stop,因为这个相当于把线程直接杀死,比如linxu的kill -9,不安全

3,线程的复位

3.1,Thread.interrupted()

import java.util.concurrent.TimeUnit;
/**
 * Created by huhuba on 2019/11/30.
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            while(true){
                if(Thread.currentThread().isInterrupted()){
                    System.out.println("before:"+Thread.currentThread().isInterrupted());
                    Thread.interrupted();
                    System.out.println("after:"+Thread.currentThread().isInterrupted());
                }
            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
    }
}

3.2,InterruptedException

import java.util.concurrent.TimeUnit;
/**
 * Created by huhuba on 2019/11/30.
 */
public class Test {
    static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                try {
                    Thread.sleep(1000);//中断一个处于阻塞状态的异常,如join,wait,queue.take...都会抛异常
                   System.out.println("demo");//中断之后依然在执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i++;
            }
            System.out.println("i:"+i);
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();//执行之后,会先去复位,然后抛出一个异常
        System.out.println(thread.isInterrupted());//false
    }
}

为什么需要复位?(没搞懂)

因为Thread.interrupted()属于当前线程对外部的一种回应,表示已经收到信号,但是不会立即中断。

--可以在异常中跳出循环,自然结束这个线程(还是不会立即停止当前线程)

正当手段结束阻塞:

wait--notify

sleep--倒计时

join--notify

 

并行和并发:

一条马路4车道,并行数是4

并发数是这条马路上能跑多少车,比如40辆车(再多就会拥堵)

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值