面试题_http调用后端接口是一个线程吗-程序员宅基地

技术标签: 面试题  

java的数据结构及优缺点:

数据结构: 优点: 缺点:

数组 插入快 查找慢,删除慢,大小固定,只能存储单一元素

有序数组 比无序数组查询快 插入慢,删除慢,大小固定,只能存储单一元素

栈 提供后劲先出的存储方式 存取其他项很慢

队列 提供先进先出的存取方式 存取其他项很慢

链表 插入快,删除快 查找慢

二叉树 如果树是平衡的,则查找,插入删除都快 删除算法复杂

红黑树 查找,删除,插入都快,树总是平衡的,算法复杂 算法复杂

2-3-4树 查找,删除,插入都快,树总是平衡的,类似的树对磁盘存储有效 算法复杂

哈希表 如果关键字已知则存取极快 删除慢,如果不知道关键字存取慢,对存储空间使用不充分

堆 插入删除快,对最大数据项存取快 对其他数据项存取慢

图 对现实世界建模 有些算法慢且复杂

排序算法:

http://www.cnblogs.com/eniac12/p/5329396.html

比较排序:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序

非比较排序:计数排序,基数排序,桶排序

冒泡排序:

1.比较相邻的元素,如果前一个比后一个大,就把他们两个调换位置

2.对每一对相邻元素做同样的工作,从开始第一队到结尾的最后一对,这步做完后,最后的元素会是最大的数

3.针对所有的元素重复以上的步骤,除了最后一个

4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一数字需要比较

#include <stdio.h>
C语言方法
// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- 如果能在内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,可以把最优时间复杂度降低到O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

void Swap(int A[], int i, int j)
{
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

void BubbleSort(int A[], int n)
{
    for (int j = 0; j < n - 1; j++)         // 每次最大元素就像气泡一样"浮"到数组的最后
    {
        for (int i = 0; i < n - 1 - j; i++) // 依次比较相邻的两个元素,使较大的那个向后移
        {
            if (A[i] > A[i + 1])            // 如果条件改成A[i] >= A[i + 1],则变为不稳定的排序算法
            {
                Swap(A, i, i + 1);
            }
        }
    }
}

int main()
{
    int A[] = { 6, 5, 3, 1, 8, 7, 2, 4 };    // 从小到大冒泡排序
    int n = sizeof(A) / sizeof(int);
    BubbleSort(A, n);
    printf("冒泡排序结果:");
    for (int i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}
java语言实现冒泡排序
	public static void BubbleSort(int[] arr)
	{
		int temp;// 定义一个临时变量
		for (int i = 0; i < arr.length - 1; i++)
		{// 冒泡趟数
			for (int j = 0; j < arr.length - i - 1; j++)
			{
				if (arr[j + 1] < arr[j])
				{
					temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
			System.out.println("第" + (i + 1) + "轮冒泡排序:" + Arrays.toString(arr));
		}
	}

	public static void main(String[] args)
	{
		int arr[] = new int[] { 6, 5, 3, 1, 8, 7, 2, 4 };
		BubbleSort(arr);
		System.out.println("最终结果:" + Arrays.toString(arr));
	}

SpringMVC的执行流程:

1.用户发送请求到前端控制器dispatcherservlet

2.dispatcherservlet调用handlerMapping处理器映射器–找到相关的Controller

3.dispatcherservlet调用handleradapter处理器适配器–找到controller中相关的方法返回ModelAndView

4.dispatcherservlet请求解析视图,调用ViewResolver视图解析器–返回view对象

5.最后dispatcherservlet渲染视图–视图jsp,freemarker等

SpringMVC的三大组件:

处理器映射器HandlerMapping,处理器适配器HandlerAdapter,视图解析器ViewResolver

struts2的执行流程:

https://www.cnblogs.com/sunTin/p/6682041.html

Struts2和SpringMVC的区别:

1.SpringMVC的入口是一个前端控制器–dispatcherservlet

Struts2的入口是一个filter过滤器–StrutsPrepareAndExecuteFilter

2.struts2通过在action类中定义成员变量接受参数(属性驱动和模型驱动)–只能是多例模式管理

SpringMVC通过在controller方法中定义形参接受参数,可以使用单例模式

3.SpringMVC是基于方法开发的,注解开发使用RequestMapping将URL和方法进行映射,如果通过URL可以找到controller中的方法,则生成一个处理器对象handler(只有一个method)

Struts2是基于类开发的,每个请求创建一个action实例,实例中有多个方法

4.Struts2使用值栈存储请求和响应的数据,通过OGNL存取数据

SpringMVC通过参数绑定将request请求内容解析,并给方法形参赋值

5.Struts2和SpringMVC的速度都是相当的,但是struts2的漏洞比较多

Hibernate和Mybatis区别:

共同点:

1.都是通过SessionFactoryBuilder由xml配置文件生成SessionFactory,由SessionFactory生成Session,由session来开启执行事务和SQL语句

2.都支持JDBC(java database connectivity:数据库连接)和JTA事务处理。(Java Transaction API:java事务API(Application Programming Interface:应用程序编程接口))

注意:JDBC和JTA都是增强数据库访问能力

3.都是基于ORM(Object Relational Mapping:对象关系映射)思想解决实体类和数据库的映射问题

不同点:

1.sql方面:

mybatis通过mapper.xml维护映射关系,需要手动编写SQL,更加灵活,SQL调优更容易些

hibernate有更好的封装性,开发效率高,SQL调优费力,手动调优时,开发效率低

hibernate的hql数据库移植性更好,体现在强壮性

hibernate在级联删除的时候效率低,数据量大表多的时候,基于关系操作就很复杂

2.缓存方面:

都可以是使用第三方的缓存,hibernate有更好的二级缓存机制

一级缓存:session级别

二级缓存:sessionFactory级别(使用ehcache的缓存包,需要配置ehcache.xml)

hibernate的缓存机制:https://www.cnblogs.com/xiaoluo501395377/p/3377604.html

常用的设计模式:

23种设计模式:https://www.cnblogs.com/geek6/p/3951677.html

数据库的优化:

https://blog.csdn.net/zhoupan301415/article/details/78257783

1.建立索引:避免全表扫描,首先考虑在where以及order by涉及的列上建立索引

2.分库分表分区

分库:读写分离

分表:

分区

3.数据库引擎:innodb和myisam

4.预处理:实时数据-放到缓存中,前一天的数据-定时任务做报表,全文检索

5.mysql 的like查询:不要使用%str% 可以使用str%

关于高并发:

搭建集群,添加缓存,添加mq,建立页面静态化

负载均衡:

https://blog.csdn.net/github_37515779/article/details/79953788

https://blog.csdn.net/tTU1EvLDeLFq5btqiK/article/details/81369904

1.http负载均衡

2.DNS负载均衡

3.反向代理负载均衡—真正意义上的负载均衡

J2EE的13种核心技术:

https://www.cnblogs.com/xingzc/p/5759915.html

1.JDBC(java database connectivity):为访问不同数据库提供一种统一的路径

2.JNDI(Java Name and Directory Interface)

JNDI API被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源如DNS和LDAP,本地文件系统,或应用服务器中的对象。

3.EJB(Enterprise JavaBean)

J2EE技术之所以赢得媒体广泛重视的原因之一就是EJB。它们提供了一个框架来开发和实施分布式商务逻辑,由此很显著地简化了具有可伸缩性和高度复杂的企业级应用的开发。EJB规范定义了EJB组件在何时如何与它们的容器进行交互作用。容器负责提供公用的服务,例如目录服务、事务管理、安全性、资源缓冲池以及容错性。但这里值得注意的是,EJB并不是实现J2EE的唯一途径。正是由于J2EE的开放性,使得有的厂商能够以一种和EJB平行的方式来达到同样的目的。

4.RMI(Remote Method Invoke)

调用远程对象上的方法。它使用了序列化方式在客户端和服务器端传递数据。RMI是一种被EJB使用的更底层的协议。

5.Java IDL/CORBA

在Java IDL的支持下,开发人员可以将Java和CORBA集成在一起。他们可以创建Java对象并使之可在CORBA ORB中展开,或者他们还可以创建Java类并作为和其它ORB一起展开的CORBA对象的客户。后一种方法提供了另外一种途径,通过它Java可以被用于将你的新的应用和旧的系统相集成。

6.JSP(Java Server Pages)

JSP页面由HTML代码和嵌入其中的Java代码所组成。服务器在页面被客户端所请求以后对这些Java代码进行处理,然后将生成的HTML页面返回给客户端的浏览器。

7.Java Servlet

Servlet是一种小型的Java程序,它扩展了Web服务器的功能。作为一种服务器端的应用,当被请求时开始执行,这和CGI Perl脚本很相似。Servlet提供的功能大多与JSP类似,不过实现的方式不同。JSP通常是大多数HTML代码中嵌入少量的Java代码,而servlets全部由Java写成并且生成HTML。

8.XML(Extensible Markup Language)

XML是一种可以用来定义其它标记语言的语言。它被用来在不同的商务过程中共享数据。

XML的发展和Java是相互独立的,但是,它和Java具有的相同目标正是平台独立性。通过将Java和XML的组合,您可以得到一个完美的具有平台独立性的解决方案。

9.JMS(Java Message Service)

JMS是用于和面向消息的中间件相互通信的应用程序接口(API)。它既支持点对点的域,又支持发布/订阅(publish/subscribe)类型的域,并且提供对下列类型的支持:经认可的消息传递,事务型消息的传递,一致性消息和具有持久性的订阅者支持。JMS还提供了另一种方式来对您的应用与旧的后台系统相集成。

10.JTA(Java Transaction Architecture)

JTA定义了一种标准的API,应用系统由此可以访问各种事务监控。

11.JTS(Java Transaction Service)

JTS是CORBA OTS事务监控的基本的实现。JTS规定了事务管理器的实现方式。该事务管理器是在高层支持Java Transaction API (JTA)规范,并且在较底层实现OMG OTS specification的Java映像。JTS事务管理器为应用服务器、资源管理器、独立的应用以及通信资源管理器提供了事务服务。

12.JavaMail

JavaMail是用于存取邮件服务器的API,它提供了一套邮件服务器的抽象类。不仅支持SMTP服务器,也支持IMAP服务器。

13.JAF(JavaBeans Activation Framework)

JavaMail利用JAF来处理MIME编码的邮件附件。MIME的字节流可以被转换成Java对象,或者转换自Java对象。大多数应用都可以不需要直接使用JAF。

jQuery的几种ajax方式对比:

jquery的ajax方式有如下几种:

  1. $.post(url,params,callback);
  2. $.getJSON(url,params,callback);
  3. $.ajax();
  4. $.load(url,params,callback);

第一种:采用post方式提交,中文参数无需转码,在callback中如果获取json字符串,还需转换一下

$.post(url,
                            {id: id,
                            code: code,
                             companyId:companyId 
                             },
                        function (data){
                            showCompanyRadialDataListdatalist
                            });

这个datalist为从后台取回来的数据List。

function showCompanyRadialDataList(datalist){
 var obj = eval(datalist);  
}//这个eval可以将data转成json串。方便后面取值。
如:
    for (var i =0 ; i< obj.length ;i++){
          $("td:eq(1)",$tr).htmlobj[i].nuclide);//这里可以用json方式取    datalist里面的数据
     }

第二种方式:getJSON采取get方式,如果params参数里面有中文的话,需要先转码

$.getJSON(url,param,function(jsondata){
这里返回的jsondata可以直接取不用再转换了。
如:jsondata[0].nuclide
}

第三种方式:$.ajax

$.ajax({
        url: url,//地址
        data: data,//参数
        type: 'POST',//提交方式 可以选择post/get 推荐post 
             async: false,//同步异步 
        dataType: 'json',//返回数据类型 
        success:function(data){
            accidentList = data.list;
           //这里可以直接取data里面的数据了,因为设置返回值为json方式。               
        }
    });

java中i+1<i的情况:

这个和java中的数值表示有关系,带符号的数都有最大值,到了最大值之后就变成负数了,可以看看java中负数的表示方法。原理讲了,下面给个例子:

int i = Integer.MAX_VALUE;
int j = i+1;
System.out.println(j<i);

自动装箱和自动拆箱:

装箱就是自动将基本数据类型转换为包装器类型;

拆箱就是自动将包装器类型转换为基本数据类型。

面向对象:

1.封装:基于类的属性,有private修饰的属性,生成get,set方法供外界调用

2.继承:

3.抽象:被abstrace修饰的类称为抽象类

4.多态:是指对非静态方法的多态,父类的引用来调用子类的方法

Hibernate的五种检索方式:

https://blog.csdn.net/stupid_java_learner/article/details/52191365

1.导航对象图检索方式。(根据已经加载的对象,导航到其他对象。)

2.OID检索方式。(按照对象的OID来检索对象。)

3.HQL检索方式。(使用面向对象的HQL查询语言。)

4.QBC检索方式。(使用QBC(Qurey By Criteria) API来检索对象。)

5.本地SQL检索方式。(使用本地数据库的SQL查询语句。)

${}和#{}的区别:

1.简单数据类型的话,都是占位符,$符里边只能写value,#符可以写任意的名字

2.${}有sql注入的风险,是字符串直接在sql语句的拼接,#的占位符是?,然后将传入的东西写入

3.#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和
jdbc类型转换,#{}的可以有效防止sql注入。#{}可以接收简单类型值或pojo属性值。

如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

4.${}表示拼接字符串,可以将parametertype传入的内容拼接在sql中且不进行jdbc类型转换,

${}可以接收简单类型值的或pojo属性值,如果parametertype传输的是单个简单类型值,{}中只能是value

MVC:

Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。

通常模型对象负责在数据库中存取数据。

View(视图)是应用程序中处理数据显示的部分。

通常视图是依据模型数据创建的。

Controller(控制器)是应用程序中处理用户交互的部分。

通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

简单的登录注册:

https://www.cnblogs.com/ktao/p/8387033.html

Map的key和value可以存null值吗?

hashMap是可以存null的,hashtable是不可以的

Map的key值存实体类对象应该注意什么?

实体类需要重写equals方法和hashcode方法

java线程sleep()和wait()方法的区别:

sleep:
让当前线程在指定时间内睡眠, 时间结束后继续执行
是Thread类的静态方法
不会释放锁
wait:
让当前线程等待, 直到有人唤醒
是Object类的非静态方法
会立刻释放锁

注意:wait的线程必须要有某个线程调用了notify才能唤醒, 如果所有的线程都wait了, 那程序整个就全都在
等待了.

AMQ的问题:

1.amq是没有返回值的,但是可以设置ack机制,问答机制,有返回值,但是解耦合就达不到效果了

2.queue和topic模式都可以设置ack机制,如果是topic的话,就会有好多个返回值

map的数据存储方式:

http://blog.sina.com.cn/s/blog_1634a41230102wyh9.html

是数组和链表的组合方式实现的

freemarker比较jsp的优缺点:

freemarker的优点:

1.分离表现层和业务层

jsp可以在前台编写业务逻辑代码,导致内容凌乱,可读性差,增加后期的维护难度

freemarker : 模板+数据模型 = 输出,仅仅负责页面表现,去掉了繁琐的业务逻辑

2.提高开发效率:

jsp在第一次执行的时候需要转换成servlet类,之后的每次修改都需要编译和转换,开发效率低

freemarker模板技术不存在编译和转换的问题,开发效率高

3.分工明确

jsp前后端代码写到一起,耦合度很高,前台的需要熟悉后台的环境,需要去调试,后台的同理

freemarker前后端完全分离,互不影响

4.简单易用,功能强大

freemarker支持jsp标签,宏定义比jsp方便,同时内置了大量常用功能

freemarker的缺点:

1.应用freemarker模板技术,修改模板后,可能会出现无法及时生成html,会看到过期数据的可能

2.freemarker中的变量必须要赋值,如果不赋值就会抛出异常

3.freemarker中的map的key必须是string类型的,其他数据类型的无法操作

4.freemarker不支持集群操作,为了编程的方便,把序列化的东西放在session中,如session,request等,在开发中确实方便,如果放在集群中就会报错

单例和多例的区别:

单例优点:

1.单例模式中只存在一个实例,减少内存开销,特别是需要频繁的创建和销毁时,单例模式就特别明显了

2.由于只有一个实例,减少系统的开销

3.单例模式可以避免对资源的多重占用

4.单例模式可以在系统设置全局的访问点,优化和共享资源访问

缺点:

单例模式一般没有接口,扩展很困难,如果要扩展,除了修改代码没有别的路径可以选择

多例缺点:

1.每次调用都会是一个新的实例对象,比较消耗内存

为什么用单例、多例:

之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;

之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
用单例和多例的标准只有一个:
当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;

何时用单例?何时用多例?

对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;
另外要说一下,并不是说service或dao一定是单例,标准同上边所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;

unicode和hashcode的区别:

hashcode:hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值

unicode:Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等

常见的状态码:

https://www.cnblogs.com/tomcuper/p/7943051.html

200:成功

302:重定向

304:浏览器的缓存和服务器数据一样,直接返回

400:请求错误,参数转换错误

404:找不到路径

500:服务器内部错误—代码写错了

AOP的表现:

1.事务2.缓存3.日志

JDK和cglib动态代理的区别:

https://blog.csdn.net/yhl_jxy/article/details/80635012

1.jdk的动态代理的类必须实现接口

2.cglib的动态代理的类不用实现接口,面向。class文件的动态代理

线程的不安全体现:

是由全局变量和静态变量引起的

如果多个线程同时执行写操作,需要考虑线程同步,一般采用加锁机制

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所读到的数据是脏数据

解决方法:https://blog.csdn.net/ai_xiangjuan/article/details/74906175

对象序列化:

序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.

java提供了序列化接口,只要实现了Serializable接口,就可将java对象序列化成字节,然后以流的形式传输,然后在远端再反序列化成对象,这就达到了传输消息的目的.

这种序列化存在一些缺陷:

1不能跨语言,2,序列化体积大

抽象类和接口的应用选择:

抽象是对类的抽象,是一种设计模板

接口是行为的抽象,是一种行为的规范

接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。

类可以是实现多个接口,但是只能继承一个抽象类

Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。

Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。

jdk8中的接口也可以有一个默认的真实的方法

接口只能有public修饰,成员变量只能用public static final修饰

ArrayList list = new ArrayList(20);扩容几次?

ArrayList的默认初始容量为10,当然也可以自定义指定初始容量,自定义的容量的情况下是不会扩充的,随着动态的向其中添加元素,其容量可能会动态的增加,那么扩容的公式为:

新容量 = 旧容量/2 + 旧容量 + 1

比如:初始容量为4,其容量的每次扩充后的新容量为:4->7->11->17->26->…

附:HashMap的初始容量大小为16

jdbc:

1.连接的获取:

private static Connection getConn() {
    
    String driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://localhost:3306/samp_db";
    String username = "root";
    String password = "";
    Connection conn = null;
    try {
    
        Class.forName(driver); //classLoader,加载对应驱动
        conn = (Connection) DriverManager.getConnection(url, username, password);
    } catch (ClassNotFoundException e) {
    
        e.printStackTrace();
    } catch (SQLException e) {
    
        e.printStackTrace();
    }
    return conn;
}

2.insert

private static int insert(Student student) {
    
    Connection conn = getConn();
    int i = 0;
    String sql = "insert into students (Name,Sex,Age) values(?,?,?)";
    PreparedStatement pstmt;
    try {
    
        pstmt = (PreparedStatement) conn.prepareStatement(sql);
        pstmt.setString(1, student.getName());
        pstmt.setString(2, student.getSex());
        pstmt.setString(3, student.getAge());
        i = pstmt.executeUpdate();
        pstmt.close();
        conn.close();
    } catch (SQLException e) {
    
        e.printStackTrace();
    }
    return i;
}

3.select

private static Integer getAll() {
    
    Connection conn = getConn();
    String sql = "select * from students";
    PreparedStatement pstmt;
    try {
    
        pstmt = (PreparedStatement)conn.prepareStatement(sql);
        ResultSet rs = pstmt.executeQuery();
        int col = rs.getMetaData().getColumnCount();
        System.out.println("============================");
        while (rs.next()) {
    
            for (int i = 1; i <= col; i++) {
    
                System.out.print(rs.getString(i) + "\t");
                if ((i == 2) && (rs.getString(i).length() < 8)) {
    
                    System.out.print("\t");
                }
             }
            System.out.println("");
        }
            System.out.println("============================");
    } catch (SQLException e) {
    
        e.printStackTrace();
    }
    return null;
}

4.delete

private static int delete(String name) {
    
    Connection conn = getConn();
    int i = 0;
    String sql = "delete from students where Name='" + name + "'";
    PreparedStatement pstmt;
    try {
    
        pstmt = (PreparedStatement) conn.prepareStatement(sql);
        i = pstmt.executeUpdate();
        System.out.println("resutl: " + i);
        pstmt.close();
        conn.close();
    } catch (SQLException e) {
    
        e.printStackTrace();
    }
    return i;
}

5.update

private static int update(Student student) {
    
    Connection conn = getConn();
    int i = 0;
    String sql = "update students set Age='" + student.getAge() + "' where Name='" + student.getName() + "'";
    PreparedStatement pstmt;
    try {
    
        pstmt = (PreparedStatement) conn.prepareStatement(sql);
        i = pstmt.executeUpdate();
        System.out.println("resutl: " + i);
        pstmt.close();
        conn.close();
    } catch (SQLException e) {
    
        e.printStackTrace();
    }
    return i;
}

面试中的JVM你需要了解:

https://blog.csdn.net/qq_34337272/article/details/80294328

Java线程面试题:

50道Java线程面试题

下面是Java线程相关的热门面试题,你可以用它来好好准备面试。

1) 什么是线程? 
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。Java在语言层面对多线程提供了卓越的支持,它也是一个很好的卖点。欲了解更多详细信息请点击这里。

2) 线程和进程有什么区别? 
线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。更多详细信息请点击这里。

3) 如何在Java中实现线程? 
在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。更多详细信息请点击这里.

4) 用Runnable还是Thread? 
这个问题是上题的后续,大家都知道我们可以通过继承Thread类或者调用Runnable接口来实现线程,问题是,那个方法更好呢?什么情况下使用它?这个问题很容易回答,如果你知道Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好了。更多详细信息请点击这里。

6) Thread 类中的start() 和 run() 方法有什么区别? 
这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。更多讨论请点击这里

7) Java中Runnable和Callable有什么不同? 
Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的 call() 方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。我的博客有更详细的说明。

8) Java中CyclicBarrier 和 CountDownLatch有什么不同? 
CyclicBarrier 和 CountDownLatch 都可以用来让一组线程等待其它线程。与 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。点此查看更多信息和示例代码。

9) Java内存模型是什么? 
Java内存模型规定和指引Java程序在不同的内存架构、CPU和操作系统间有确定性地行为。它在多线程的情况下尤其重要。Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。比如,先行发生关系确保了:

线程内的代码能够按先后顺序执行,这被称为程序次序规则。 
对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则。 
前一个对volatile的写操作在后一个volatile的读操作之前,也叫volatile变量规则。 
一个线程内的任何操作必需在这个线程的start()调用之后,也叫作线程启动规则。 
一个线程的所有操作都会在线程终止之前,线程终止规则。 
一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则。 
可传递性 
我强烈建议大家阅读《Java并发编程实践》第十六章来加深对Java内存模型的理解。

10) Java中的volatile 变量是什么? 
volatile是一个特殊的修饰符,只有成员变量才能使用它。在Java并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。volatile变量可以保证下一个读取操作会在前一个写操作之后发生,就是上一题的volatile变量规则。点击这里查看更多volatile的相关内容。

11) 什么是线程安全?Vector是一个线程安全类吗? (详见这里) 
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。

12) Java中什么是竞态条件? 举个例子说明。 
竞态条件会导致程序在并发情况下出现一些bugs。多线程对一些资源的竞争的时候就会产生竞态条件,如果首先要执行的程序竞争失败排到后面执行了,那么整个程序就会出现一些不确定的bugs。这种bugs很难发现而且会重复出现,因为线程间的随机竞争。一个例子就是无序处理,详见答案。

13) Java中如何停止一个线程? 
Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程。点击这里查看示例代码。

14) 一个线程运行时发生异常会怎样? 
这是我在一次面试中遇到的一个很刁钻的Java面试题, 简单的说,如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理。

15) 如何在两个线程间共享数据? 
你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构。这篇教程《Java线程间通信》(涉及到在两个线程间共享对象)用wait和notify方法实现了生产者消费者模型。

16) Java中notify 和 notifyAll有什么区别? 
这又是一个刁钻的问题,因为多线程可以等待单监控锁,Java API 的设计人员提供了一些方法当等待条件改变的时候通知它们,但是这些方法没有完全实现。notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。我的博客有更详细的资料和示例代码。

17) 为什么wait, notify 和 notifyAll这些方法不在thread类里面? 
这是个设计相关的问题,它考察的是面试者对现有系统和一些普遍存在但看起来不合理的事物的看法。回答这些问题的时候,你要说明为什么把这些方法放在Object类里是有意义的,还有不把它放在Thread类里的原因。一个很明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。你也可以查看这篇文章了解更多。

18) 什么是ThreadLocal变量? 
ThreadLocal是Java里一种特殊的变量。每个线程都有一个ThreadLocal就是每个线程都拥有了自己独立的一个变量,竞争条件被彻底消除了。它是为创建代价高昂的对象获取线程安全的好方法,比如你可以用ThreadLocal让SimpleDateFormat变成线程安全的,因为那个类创建代价高昂且每次调用都需要创建不同的实例所以不值得在局部范围使用它,如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者不变性的情况下获得了线程安全。线程局部变量的另一个不错的例子是ThreadLocalRandom类,它在多线程环境中减少了创建代价高昂的Random对象的个数。查看答案了解更多。

19) 什么是FutureTask? 
在Java并发程序中FutureTask表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞。一个FutureTask对象可以对调用了Callable和Runnable的对象进行包装,由于FutureTask也是调用了Runnable接口所以它可以提交给Executor来执行。

20) Java中interrupted 和 isInterruptedd方法的区别? 
interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。而非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。无论如何,一个线程的中断状态有有可能被其它线程调用中断来改变。

21) 为什么wait和notify方法要在同步块中调用? 
主要是因为Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。

22) 为什么你应该在循环中检查等待条件? 
处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。因此,当一个等待线程醒来时,不能认为它原来的等待状态仍然是有效的,在notify()方法调用之后和等待线程醒来之前这段时间它可能会改变。这就是在循环中使用wait()方法效果更好的原因,你可以在Eclipse中创建模板调用wait和notify试一试。如果你想了解更多关于这个问题的内容,我推荐你阅读《Effective Java》这本书中的线程和同步章节。

23) Java中的同步集合与并发集合有什么区别? 
同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。在Java1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的扩展性。Java5介绍了并发集合像ConcurrentHashMap,不仅提供线程安全还用锁分离和内部分区等现代技术提高了可扩展性。更多内容详见答案。

24) Java中堆和栈有什么不同? 
为什么把这个问题归类在多线程和并发面试题里?因为栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用了,它要求线程从主存中读取变量的值。 
更多内容详见答案。

25) 什么是线程池? 为什么要使用它? 
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。更多内容详见这篇文章。

26) 如何写代码来解决生产者消费者问题? 
在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行消费,你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notify来解决这个问题,比较赞的办法是用Semaphore 或者 BlockingQueue来实现生产者消费者模型,这篇教程有实现它。

27) 如何避免死锁?

Java多线程中的死锁 
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

互斥条件:一个资源每次只能被一个进程使用。 
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。这篇教程有代码示例和避免死锁的讨论细节。

28) Java中活锁和死锁有什么区别? 
这是上题的扩展,活锁和死锁类似,不同之处在于处于活锁的线程或进程的状态是不断改变的,活锁可以认为是一种特殊的饥饿。一个现实的活锁例子是两个人在狭小的走廊碰到,两个人都试着避让对方好让彼此通过,但是因为避让的方向都一样导致最后谁都不能通过走廊。简单的说就是,活锁和死锁的主要区别是前者进程的状态可以改变但是却不能继续执行。

29) 怎么检测一个线程是否拥有锁? 
我一直不知道我们竟然可以检测一个线程是否拥有锁,直到我参加了一次电话面试。在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。你可以查看这篇文章了解更多。

30) 你如何在Java中获取线程堆栈? 
对于不同的操作系统,有多种方法来获得Java进程的线程堆栈。当你获取线程堆栈时,JVM会把所有线程的状态存到日志文件或者输出到控制台。在Windows你可以使用Ctrl + Break组合键来获取线程堆栈,Linux下用kill -3命令。你也可以用jstack这个工具来获取,它对线程id进行操作,你可以用jps这个工具找到id。

31) JVM中哪个参数是用来控制线程的栈堆栈小的 
这个问题很简单, -Xss参数用来控制线程的堆栈大小。你可以查看JVM配置列表来了解这个参数的更多信息。

32) Java中synchronized 和 ReentrantLock 有什么不同? 
Java在过去很长一段时间只能通过synchronized关键字来实现互斥,它有一些缺点。比如你不能扩展锁之外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具有可扩展性。你可以查看这篇文章了解更多

33) 有三个线程T1,T2,T3,怎么确保它们按顺序执行? 
在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。你可以查看这篇文章了解更多。

34) Thread类中的yield方法有什么作用? 
Yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU,执行yield()的线程有可能在进入到暂停状态后马上又被执行。点击这里查看更多yield方法的相关内容。

35) Java中ConcurrentHashMap的并发度是什么? 
ConcurrentHashMap把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样在多线程情况下就能避免争用。欲了解更多并发度和内部大小调整请阅读我的文章How ConcurrentHashMap works in Java。

36) Java中Semaphore是什么? 
Java中的Semaphore是一种新的同步类,它是一个计数信号。从概念上讲,从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动。信号量常常用于多线程的代码中,比如数据库连接池。更多详细信息请点击这里。

37)如果你提交任务时,线程池队列已满。会时发会生什么? 
这个问题问得很狡猾,许多程序员会认为该任务会阻塞直到线程池队列有空位。事实上如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常。

38) Java线程池中submit() 和 execute()方法有什么区别? 
两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。更多详细信息请点击这里。

39) 什么是阻塞式方法? 
阻塞式方法是指程序会一直等待该方法完成期间不做其他事情,ServerSocket的accept()方法就是一直等待客户端连接。这里的阻塞是指调用结果返回之前,当前线程会被挂起,直到得到结果之后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。更多详细信息请点击这里。

40) Swing是线程安全的吗? 为什么? 
你可以很肯定的给出回答,Swing不是线程安全的,但是你应该解释这么回答的原因即便面试官没有问你为什么。当我们说swing不是线程安全的常常提到它的组件,这些组件不能在多线程中进行修改,所有对GUI组件的更新都要在AWT线程中完成,而Swing提供了同步和异步两种回调方法来进行更新。点击这里查看更多swing和线程安全的相关内容。

41) Java中invokeAndWait 和 invokeLater有什么区别? 
这两个方法是Swing API 提供给Java开发者用来从当前线程而不是事件派发线程更新GUI组件用的。InvokeAndWait()同步更新GUI组件,比如一个进度条,一旦进度更新了,进度条也要做出相应改变。如果进度被多个线程跟踪,那么就调用invokeAndWait()方法请求事件派发线程对组件进行相应更新。而invokeLater()方法是异步调用更新组件的。更多详细信息请点击这里。

42) Swing API中那些方法是线程安全的? 
这个问题又提到了swing和线程安全,虽然组件不是线程安全的但是有一些方法是可以被多线程安全调用的,比如repaint(), revalidate()。 JTextComponent的setText()方法和JTextArea的insert() 和 append() 方法也是线程安全的。

43) 如何在Java中创建Immutable对象? 
这个问题看起来和多线程没什么关系, 但不变性有助于简化已经很复杂的并发程序。Immutable对象可以在没有同步的情况下共享,降低了对该对象进行并发访问时的同步化开销。可是Java没有@Immutable这个注解符,要创建不可变类,要实现下面几个步骤:通过构造方法初始化所有成员、对变量不要提供setter方法、将所有的成员声明为私有的,这样就不允许直接访问这些成员、在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝。我的文章how to make an object Immutable in Java有详细的教程,看完你可以充满自信。

44) Java中的ReadWriteLock是什么? 
一般而言,读写锁是用来提升并发程序性能的锁分离技术的成果。Java中的ReadWriteLock是Java 5 中新增的一个接口,一个ReadWriteLock维护一对关联的锁,一个用于只读操作一个用于写。在没有写线程的情况下一个读锁可能会同时被多个读线程持有。写锁是独占的,你可以使用JDK中的ReentrantReadWriteLock来实现这个规则,它最多支持65535个写锁和65535个读锁。

45) 多线程中的忙循环是什么? 
忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存,在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。

46)volatile 变量和 atomic 变量有什么不同? 
这是个有趣的问题。首先,volatile 变量和 atomic 变量看起来很像,但功能却不一样。Volatile变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它并不能保证原子性。例如用volatile修饰count变量那么 count++ 操作就不是原子性的。而AtomicInteger类提供的atomic方法可以让这种操作具有原子性如getAndIncrement()方法会原子性的进行增量操作把当前值加一,其它数据类型和引用变量也可以进行相似操作。

47) 如果同步块内的线程抛出异常会发生什么? 
这个问题坑了很多Java程序员,若你能想到锁是否释放这条线索来回答还有点希望答对。无论你的同步块是正常还是异常退出的,里面的线程都会释放锁,所以对比锁接口我更喜欢同步块,因为它不用我花费精力去释放锁,该功能可以在finally block里释放锁实现。

48) 单例模式的双检锁是什么? 
这个问题在Java面试中经常被问到,但是面试官对回答此问题的满意度仅为50%。一半的人写不出双检锁还有一半的人说不出它的隐患和Java1.5是如何对它修正的。它其实是一个用来创建线程安全的单例的老方法,当单例实例第一次被创建时它试图用单个锁进行性能优化,但是由于太过于复杂在JDK1.4中它是失败的,我个人也不喜欢它。无论如何,即便你也不喜欢它但是还是要了解一下,因为它经常被问到。你可以查看how double checked locking on Singleton works这篇文章获得更多信息。

49) 如何在Java中创建线程安全的Singleton? 
这是上面那个问题的后续,如果你不喜欢双检锁而面试官问了创建Singleton类的替代方法,你可以利用JVM的类加载和静态变量初始化特征来创建Singleton实例,或者是利用枚举类型来创建Singleton,我很喜欢用这种方法。

50) 写出3条你遵循的多线程最佳实践 
这种问题我最喜欢了,我相信你在写并发代码来提升性能的时候也会遵循某些最佳实践。以下三条最佳实践我觉得大多数Java程序员都应该遵循:

给你的线程起个有意义的名字。 
这样可以方便找bug或追踪。OrderProcessor, QuoteProcessor or TradeProcessor 这种名字比 Thread-1. Thread-2 and Thread-3 好多了,给线程起一个和它要完成的任务相关的名字,所有的主要框架甚至JDK都遵循这个最佳实践。 
避免锁定和缩小同步的范围 
锁花费的代价高昂且上下文切换更耗费时间空间,试试最低限度的使用同步和锁,缩小临界区。因此相对于同步方法我更喜欢同步块,它给我拥有对锁的绝对控制权。 
多用同步类少用wait 和 notify 
首先,CountDownLatch, Semaphore, CyclicBarrier 和 Exchanger 这些同步类简化了编码操作,而用wait和notify很难实现对复杂控制流的控制。其次,这些类是由最好的企业编写和维护在后续的JDK中它们还会不断优化和完善,使用这些更高等级的同步工具你的程序可以不费吹灰之力获得优化。 
多用并发集合少用同步集合 
这是另外一个容易遵循且受益巨大的最佳实践,并发集合比同步集合的可扩展性更好,所以在并发编程时使用并发集合效果更好。如果下一次你需要用到map,你应该首先想到用ConcurrentHashMap。
51) 如何强制启动一个线程? 
这个问题就像是如何强制进行Java垃圾回收,目前还没有觉得方法,虽然你可以使用System.gc()来进行垃圾回收,但是不保证能成功。在Java里面没有办法强制启动一个线程,它是被线程调度器控制着且Java没有公布相关的API。

52) Java中的fork join框架是什么? 
fork join框架是JDK7中出现的一款高效的工具,Java开发人员可以通过它充分利用现代服务器上的多处理器。它是专门为了那些可以递归划分成许多子模块设计的,目的是将所有可用的处理能力用来提升程序的性能。fork join框架一个巨大的优势是它使用了工作窃取算法,可以完成更多任务的工作线程可以从其它线程中窃取任务来执行。

53) Java多线程中调用wait() 和 sleep()方法有什么不同? 
Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42786855/article/details/86634674

智能推荐

耕作方式对微生物群落的影响_cropping practices manipulate abundance patterns o-程序员宅基地

文章浏览阅读3.2k次,点赞2次,收藏10次。Cropping practices manipulate abundance patterns of root and soil microbiome members paving the way to smart farming C:普通耕作 O:有机耕作NT:免耕 RT:少耕 IT:密集耕作C-IT C-NT O-IT O-RT Hartman et al. M..._cropping practices manipulate abundance patterns of root and soil microbiome

tableau表计算--柏拉图曲线_tableau柏拉图-程序员宅基地

文章浏览阅读1.5k次。各个领域都存在着二八定律:比如零售行业,80%的利润可能来自其中20%的用户。今天学到了怎么用tableau来做一个这样的柏拉图曲线。成果图:开始吧把利润、客户名称分别拖到行、列;客户名称拖到标记里的详细详细:2.选择【客户名称】然后点击排序3.右键选择【利润】添加表计算4.上一步得到了利润排序后累计百分比的曲线,如果你想看看是否在利润达到累计80%时客户数在20%左右那就..._tableau柏拉图

【linux】串口编程(二)——非阻塞接收_linux串口非阻塞例程-程序员宅基地

文章浏览阅读2k次。项目中很少会使用阻塞接收,一般都是select+read监听模式来实现非阻塞接收。 使用selece时,需要处理一些异常情况的返回,比如:系统中断产生EINTR错误;超时错误ETIMEDOUT。 使用read时,需要处理读取时可能出现的错误,比如:对方关闭连接(ECONNRESET),连接被拒绝(ECONNREFUSED),文件描述符错误(EBADF)等_linux串口非阻塞例程

Qt 5.9.5 webengine 开发_webengine 淘汰-程序员宅基地

文章浏览阅读9k次。QtWebkits在Qt5.6以上版本被淘汰了,目前而言,QWebEngine有以下缺点:MinGW版本的Qt不支持,即便是Qt5.9.5版本以上也是不支持的。仅仅支持MSVC版本,接口暂时不丰富,无法和QWebFrame进行交互(使用了新的QWebChannel和QWebEnginePage组合进行交互)在使用的时间安装新版本的Qt要安装Qt MSVC版本的,记得选择webengine组件在ex..._webengine 淘汰

BUUCTF Misc Page2-6部分题目_b0d3e5f34e36b189b47a1a57a0a43ba4.png-程序员宅基地

文章浏览阅读6.7w次,点赞4次,收藏29次。BUUCTF Misc Page2-6部分题目_b0d3e5f34e36b189b47a1a57a0a43ba4.png

云服务器、宝塔面板配置express、mySQL_宝塔安装express-程序员宅基地

文章浏览阅读3.6k次。1.服务器数据库环境搭建新建数据库实测服务器为centOS系统,这里使用的是宝塔控制面板配置环境登录宝塔进入面板点击左侧数据库,如果没有安装需要进入软件商店进行安装宝塔面板新建数据库,填写要新建的数据库名称、用户名和密码导入数据库导入方式一:以SQL文件方式导入● 将本地数据库导出SQL文件● 宝塔面板中左侧“数据库”,点击导入,选择要导入的sql文件并上传到数据库中● 导入成功后点击“工具”即可查看数据库中所有导入的表信息导入方式二:用可视化工具Navi_宝塔安装express

随便推点

Eclipse 扁平化滚动条、背景色美化_jeeeyul is themes-程序员宅基地

文章浏览阅读1.7k次。Eclipse 扁平化滚动条、背景色美化_jeeeyul is themes

[Vue warn]: Error in onLoad hook (Promise/async): “ReferenceError: hpvPack is not defined“-程序员宅基地

文章浏览阅读1.6k次。#Error in onLoad hook (Promise/async): "ReferenceError: hpvPack is not defined"#vue#uniapp框架开发#_error in onload hook (promise/async)

经典算法问题 - 最大连续子数列和_c语言给定n个整数的数列,其中有可能是正数和负数,找出其中一个连续子数列-程序员宅基地

文章浏览阅读716次。原文:最大连续子数列和一道很经典的算法问题,给定一个数列,其中可能有正数也可能有负数,我们的任务是找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大。我们一起用多种方式,逐步优化解决这个问题。为了更清晰的理解问题,首先我们先看一组数据:8-2 6 -1 5 4 -7 2 3第一行的8是说序列的长度是8,然后第二行有8个数字,即待计算的序列。对于这个序列,我们的答案应该是14,..._c语言给定n个整数的数列,其中有可能是正数和负数,找出其中一个连续子数列

CH32V307 LVGL移植笔记-程序员宅基地

文章浏览阅读1.1k次,点赞3次,收藏7次。第二步:把lv_conf_template.h 文件名修改成 lv_conf.h,同时打开lv_conf.h 文件,修改条件编译指令,把#if 0 修改成#if 1。移植前准确,CH32V307核心板,1.8"的TFT显示屏。第六步:测试,在main.c中包含#include "lvgl.h"和#include "lv_port_disp_template.h",并加入以下测试代码。第三步:添加头文件路径,右键选中工程,弹出菜单中选择属性,依次打开下图所示界面,选择从worksapce中添加路径信息。_ch32v307

我的Qt作品(11)使用Qt+OpenCV实现一个带旋转角度的NCC灰度模板匹配演示软件_灰度模板旋转匹配-程序员宅基地

文章浏览阅读9.8k次,点赞10次,收藏97次。使用Qt+OpenCV自己写了一个带旋转角度的NCC灰度模板匹配算子。算子的原理是基于NCC灰度匹配。在opencv代码中,matchTemplate函数保存在文件imgproc文件夹下的templmatch.cpp中,NCC算子的计算方式是cv::TM_CCOEFF_NORMED。https://github.com/opencv/opencv/blob/4.5.5/modules/imgproc/src/templmatch.cpp部分头文件#ifndef CNCCMATCH_H#d_灰度模板旋转匹配

IntelliJ IDEA 安装教程_idea crack.jar-程序员宅基地

文章浏览阅读321次。1:在官网上下载IntelliJ IDEA 开发工具https://www.jetbrains.com/idea/download/#section=windows2:选择自己的电脑系统对于的下载包点击下载按钮下载下载之后开始安装3:一般我会保存在d盘里面,不建议放在c盘,因为会造成电脑卡顿的问题,并且记住安装路径,后面需要用到。D:\IntelliJ IDEA 2018.3...._idea crack.jar

推荐文章

热门文章

相关标签