• 并发知识(1)——线程基础知识


    创建线程有几种方式:

    1. 自定义类继承Thread(如下面的AThread),然后使用Thread.start方法启动线程
    2. 创建类,实现Runnable,通过Thread的构造函数来启动,有时也用于ThreadPoolExecutor线程池的一些execute方法中
    3. Callable,提到Callable就需要知道Future,通常情况下Callable用于线程池execute或submit方法中,获取线程的返回结果。
      FutureTask
    4. Executors框架的几个常用方法,调用execute或者submit方法即可。
    public class CreateThread {
        @Test
        public void useThread() throws InterruptedException {
            AThread newThread = new AThread("线程1");
            newThread.start();
        }
    
        @Test
        public void implementsRunnable() {
            new Thread(()->{
                System.err.println(Thread.currentThread().getName() + " is running.");
            }, "线程2").start();
        }
    
        @Test
        public void useCallable() throws ExecutionException, InterruptedException {
            Callable<String> callable = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return "use callable test.";
                }
            };
            ExecutorService executorService = Executors.newFixedThreadPool(1);
            Future<String> future = executorService.submit(callable);
            System.err.println(future.get());
    
        }
    
        class AThread extends Thread {
            public AThread(String name) {
                super(name);
            }
    
            @Override
            public void run() {
                System.err.println(Thread.currentThread().getName() + " is running.");
            }
        }
    }
    

    Race Condition

    知识前提:了解一下《深入理解JVM虚拟机》Chapter2.2,Java虚拟机运行时数据区。

    方法区(类变量、类信息等)、堆(heap)是线程共享的数据区;

    虚拟机栈、本地方法栈、程序计数器(唯一一个不会OOM的区域)线程隔离。

    这里以i++为例

    首先介绍一下:

    public class Test {
    
         int test1() {
            int i = 1;
            return i++;
        }
        int test2() {
            int i = 1;
           return  ++i;
        }
    }
    

    javac 编译成字节码文件,javap -verbose Test.class查看字节码信息:

    int test1();
        descriptor: ()I
        flags:
        Code:
          stack=1, locals=2, args_size=1
             0: iconst_1
             1: istore_1
             2: iload_1
             3: iinc          1, 1
             6: ireturn
          LineNumberTable:
            line 15: 0
            line 16: 2
    
      int test2();
        descriptor: ()I
        flags:
        Code:
          stack=1, locals=2, args_size=1
             0: iconst_1
             1: istore_1
             2: iinc          1, 1
             5: iload_1
             6: ireturn
          LineNumberTable:
            line 19: 0
            line 20: 2
    

    i++分为三步:iconst_1——数字1进栈,istore_1——将栈顶int型数值存入第二个局部变量,从0开始计数

    iinc 1: 加1

    注意到:i++是先load,再inc;而++i是先inc再load

    线程的几种状态

    参考《深入理解Java虚拟机》chapter12,线程状态分为5种:

    • 新建(New):创建后未运行的线程
    • 运行(Runnable):Runnable包含了操作系统线程状态中的Running和Ready,有可能正在执行,也有可能等待着CPU为它分配执行时间。
    • 无限期等待(Waiting):无等待时间的Object.wait()方法,Thread.join()方法,LockSupport.park()方法。
    • 限期等待(Timed Waiting):Thread.sleep(),带timeout参数的wait(),join()方法,LockSupport.parkNanos(),LockSupport.parkUntil();
    • 阻塞(Blocked):等待获取一个排它锁。
    • 结束(Terminated):已终止线程的线程状态。

    各状态之间的转换如下图(来自:线程的状态转换以及基本操作):

    当你准备好了,机会来临的时候,你才能抓住
  • 相关阅读:
    今天不说技术,说说中国的十二生肖告诉了我们什么?这就是我们的祖先!
    JS函数的原型及对象,对象方法,对象属性的学习
    C#3.0特性之列表对象的赋值更容易
    读本地图像文件,在上面写一些文件,再传到WWW服务器上
    【Visual C++】vs2008/2005正确打开vs2010所创建项目的几种方法
    高级Swing容器(一)
    助你成长为优秀的程序员 杰出的软件工程师、设计师、分析师和架构师
    Root Pane Containers(一)
    【Visual C++】关于无法打开包括文件:“StdAfx.h”或者意外结尾的错误解决方案
    20年工作经验的架构师写给程序员的一封信
  • 原文地址:https://www.cnblogs.com/studentytj/p/11182766.html
Copyright © 2020-2023  润新知