首页 文章 精选 留言 我的

精选列表

搜索[PostgreSQL扩展],共10000篇文章
优秀的个人博客,低调大师

Java并发编程(02):线程核心机制,基础概念扩展

一、线程基本机制 1、概念描述 并发编程的特点是:可以将程序划分为多个分离且独立运行的任务,通过线程来驱动这些独立的任务执行,从而提升整体的效率。下面提供一个基础的演示案例。 2、应用案例 场景:假设有一个容器集合,需要拿出容器中的每个元素,进行加工处理,一般情况下直接遍历就好,如果数据偏大,可以根据线程数量对集合切割,每个线程处理一部分数据,这样处理时间就会减少很多。 public class ExtendThread01 { public static void main(String[] args) { List<Object> dataList = new ArrayList<>() ; dataList.add("A"); dataList.add("B"); dataList.add("C"); // 把一个大的集合按照每个子集合的2个元素切割 List<List<Object>> splitList = splitList(dataList,2); for (List<Object> list:splitList){ System.out.println(list); } // 多线程处理 for (List<Object> childList:splitList){ ListTask listTask = new ListTask(childList) ; Thread runThread = new Thread(listTask); runThread.start(); } } /** * List 集合切割 */ private static List<List<Object>> splitList (List<Object> list, int childSize) { if (list == null || list.size() == 0 || childSize < 1) { return null; } List<List<Object>> result = new ArrayList<>(); int size = list.size(); int count = (size + childSize - 1) / childSize ; for (int i = 0; i < count; i++) { List<Object> subList = list.subList(i * childSize, ((i + 1) * childSize > size ? size : childSize * (i + 1))); result.add(subList); } return result; } } class ListTask implements Runnable { private List<Object> list ; public ListTask (List<Object> list){this.list=list;} @Override public void run() { for (Object object:list){ System.out.println(Thread.currentThread().getName()+"=="+object); } } } 注意:这里案例只是对场景原理的实现,在开发中,是不允许这种操作的,需要使用线程池处理,后续会说。如果集合没有控制好,导致大量创建Thread线程,导致内存溢出。 二、线程停止启动 1、基础流程 线程启动后执行任务方法,在执行过程中可以被阻塞,休眠,唤醒,停止等一系列状态操作。 线程休眠作用:当线程一部分任务执行完毕后进入休眠(阻塞)状态,线程调度器可以切换到另外线程,这对分布任务的执行相对公平。 2、使用案例 public class ExtendThread02 { public static void main(String[] args) { StopThread stopThread = new StopThread() ; stopThread.start(); // 标记当前线程停止信号,且抛出中断异常,但没有停止 stopThread.interrupt(); // 判断当前线程是否已经是终止状态 System.out.println("1=="+stopThread.isInterrupted()); // 清除当前线程的终止信号 System.out.println("2=="+stopThread.interrupted()); // 再次判断当前线程状态 System.out.println("3=="+stopThread.isInterrupted()); System.out.println("main end ..."); } } class StopThread extends Thread { @Override public void run() { for (int i = 0 ; i < 10 ; i++){ try { System.out.println(Thread.currentThread().getId()+"="+i); // 线程阻塞1秒 Thread.sleep(1000); } catch (InterruptedException e){ e.printStackTrace(); } } } } 3、核心方法 sleep(long millis):线程休眠指定的时间,进入阻塞状态; interrupt():切换线程为中断状态,抛出中断异常,不会停止线程,可以监视线程的中断状态并定义执行策略。 interrupted():清除调用该方法线程的中断状态,也不会影响线程的执行,且返回当前执行‘stopThread.interrupted()’的线程是否中断,这里就是指main线程是否中断。 isInterrupted():判断调用该方法的线程是否已经是中断状态。 补刀一句:线程的这几个方法极其容易混淆,需要断点源码追踪一下看看,进入源码方法,调用相关API查看一下状态。(附断点图一张:) 三、线程优先级 1、基础概念 CPU执行和处理线程的顺序是不确定的,但是线程调度器倾向执行线程优先级高的线程,线程优先级高说明获取CPU资源的概率高,或者获取的执行时间分片多,但不代表优先级低的一定最后执行。 2、使用案例 public class ExtendThread03 { public static void main(String[] args) { Priority01 priority01 = new Priority01(); priority01.start(); System.out.println("priority01="+priority01.getPriority()); Priority02 priority02 = new Priority02(); priority02.start(); System.out.println("priority02="+priority02.getPriority()); priority01.setPriority(10); priority02.setPriority(1); } } class Priority01 extends Thread { @Override public void run() { for (int i = 0 ; i < 100 ; i++){ System.out.println(Thread.currentThread().getName()+";i="+i); } } } class Priority02 extends Thread { @Override public void run() { for (int a = 0 ; a < 100 ; a++){ System.out.println(Thread.currentThread().getName()+";a="+a); } } } 注意:优先级范围[MAX_PRIORITY=10,MIN_PRIORITY=1],如果超出范围会抛出IllegalArgumentException异常。 建议:通常实际开发中,是不允许轻易修改线程运行的参数,容易引发认知之外的异常。 四、线程加入 1、基本概念 如果在线程A中,执行线程B的加入方法,那么A线程就会等待线程B执行完毕再返回继续执行。 2、使用案例 public class ExtendThread04 { public static void main(String[] args) { JoinThreadA joinThreadA = new JoinThreadA() ; joinThreadA.start(); } } class JoinThreadA extends Thread { @Override public void run() { System.out.println("缺水中..."); JoinThreadB joinThreadB = new JoinThreadB() ; joinThreadB.start(); try{ joinThreadB.join(); } catch (Exception e){ e.printStackTrace(); } System.out.println("喝水中..."); } } class JoinThreadB extends Thread { @Override public void run() { System.out.println("买水中..."); try{ TimeUnit.SECONDS.sleep(2); } catch (Exception e){ e.printStackTrace(); } System.out.println("买到水..."); } } 注意:可以设置线程的加入时间join(long),毕竟等不到雪月风花,人生都是有时差,只能后会无期了。 五、本地线程 1、基本概念 本地的线程变量,底层维护ThreadLocalMap存储值: static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } 即以Key-Value键值对的方式存储数据。如果对集合容器的源码熟悉的话,这个Entry就是似曾相识感觉。 2、使用案例 public class ExtendThread05 { private static final ThreadLocal<Long> threadLocal = new ThreadLocal<>() ; private static void initBegin (){ threadLocal.set(System.currentTimeMillis()); } private static Long overTime (){ return System.currentTimeMillis()-threadLocal.get(); } public static void main(String[] args) throws Exception { ExtendThread05.initBegin(); TimeUnit.SECONDS.sleep(3); System.out.println(ExtendThread05.overTime()); } } ThreadLocal提供线程内存储变量的能力,并且绑定到当前线程,通过get和set方法就可以得到和设置当前线程对应的值。这个在web开发中是常见的应用。 六、守护线程 1、基本概念 守护线程是支持辅助型线程,主要在程序中起到调度和支持性作用,当Jvm中非守护线程全部结束,守护线程也就会结束。 2、使用案例 public class ExtendThread06 { public static void main(String[] args) throws Exception { InputStreamReader is = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(is); String value = br.readLine(); CheckThread checkThread = new CheckThread(value) ; checkThread.setDaemon(true); checkThread.start(); System.out.println("Main End ..."); } } class CheckThread extends Thread { private String spell ; public CheckThread (String spell){ this.spell = spell ; } @Override public void run() { if (spell.startsWith("cs")){ System.out.println(spell+":输入正确"); } else { System.out.println(spell+":输入错误"); } try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e){ e.printStackTrace(); } } } 注意:守护线程需要显式调用setDaemon(true);方法,这里可以看到main线程结束,整合程序就结束了,丝毫理会休眠中的守护线程。如果打断非守护线程的休眠,试试会不会抛你一脸异常? 七、线程异常处理 1、机制描述 按照Java中异常处理机制,抛异常逐级降低,线程的任务方法run没有抛异常,那重写或者实现的方法自然不能直接throws异常出去。多线程中推荐捕获异常,可以针对性处理机制。 2、使用案例 public class ExtendThread07 { public static void main(String[] args) { TryThread tryThread = new TryThread(); tryThread.setName("try-name"); // 定义运行中异常处理策略 MyExe myExe = new MyExe() ; tryThread.setUncaughtExceptionHandler(myExe); tryThread.start(); } } class TryThread extends Thread { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e){ e.printStackTrace(); } // 如何处理这里异常? Integer.parseInt("cicada") ; } } class MyExe implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName()+";异常:"+e.getMessage()); } } 通过实现UncaughtExceptionHandler接口,并且线程要指定自定义异常处理对象,也可以处理未检查的异常。 八、源代码地址 GitHub·地址 https://github.com/cicadasmile/java-base-parent GitEE·地址 https://gitee.com/cicadasmile/java-base-parent

优秀的个人博客,低调大师

Vitess 4.0 发布,MySQL 数据库集群水平扩展系统

Vitess 4.0 发布了。Vitess 是一个分布式 MySQL 工具集,它可以自动分片存储 MySQL 数据表,将单个 SQL 查询改写为分布式发送到多个 MySQL Server 上,支持行缓存(比 MySQL 本身缓存效率高)与复制容错等。 此版本主要新特性包括: 改进 SQL 查询支持 支持的 MySQL 语法的覆盖范围有了不小的进步,例如现在可以跨分片边界插入。 还支持更广泛的 SELECT 语句,包括对诸如 COUNT(DISTINCT …)不同聚合查询的支持。也可以通过 ALTER VSCHEMASQL 修改 Vitess 本身。 现在也已经开始使用常见的应用和框架测试 Vitess,并向测试套件中添加故障。目的是使从单一的 MySQL 或 MariaDB 迁移到分片的 Vitess 成为可能,而应用对此有所感知。 改进可用性 Vitess 4.0 中有许多改进,可以使新用户更容易使用: 完善 Kubernetes 和 Vagrant 的本地开发入门教程。 入门所需的配置较少,因为在许多情况下可以自动检测到 MySQL 版本。 改进了许多错误消息,并着重于确保它们处于正确的日志级别(error、warning 或 info)。 VReplication 的实验性支持 分片的缺点之一是可能不得不做出权衡取舍,例如,在具有买家和卖家的电子商务平台中,可以选择按买家分片,在这种情况下,卖家在分片系统中的查询可能会变慢。对于需要买卖双方都有效查询的应用,VReplication 提供了一种方式来订阅对每个分片进行的更改(使用 MySQL 二进制日志),并保留关键数据的冗余副本在其它分片上的可用性。可以认为此功能类似于其它商业数据库中可用的实例化视图。 此外 Vitess 4.0 还支持表等效的概念,这意味着可以指示 Vitess 从原始表或 VReplication 实例化视图中进行读取,无论哪种查询都能更快地执行。 详情查看更新说明: https://vitess.io/blog/2019-11-05-vitess-4.0-has-been-released

优秀的个人博客,低调大师

码良后端代码正式开源 —— 高扩展网页制作平台

源码部署 码良项目目前(2019/11/1)已经完全开源。因此这里说明下如何使用源码将整个项目运行起来。 项目构成 码良系统由3个项目构成,分别是gods-pen-server 码良服务端、gods-pen-admin 码良管理后台以及于7月份就已经开源的gods-pen码良编辑器。 从上述项目的名称上很容易看出各部分之功能,这里不再赘述。 其中码良编辑器和码良管理后台是 vue 项目,码良服务端是基于 egg 的 nodejs 项目。 开发环境运行 鉴于项目略多,我们开发了一个小工具来帮助您完成大部分工作,比如项目拉取、依赖安装、dev 运行等。 # 全局安装 gods-pen-cli 工具 npm install gods-pen-cli -g 运行gods-pen serve help可以看到有三个子命令。 gods-pen serve fetch 使用gods-pen serve fetch拉取代码并安装依赖。工具自动在当前目录(cwd)目录拉取项目源码(如果 git 可用,则使用git),然后依次安装项目依赖。 当然,你也可以不借助这个工具,从 github clone 项目即可。安装依赖也很简单,分别在三个项目根目录下yarn搞定。 项目配置 码良依赖了 es、redis、mysql、邮件、oss服务,因此需要配置这些服务的信息。 如果你有读过前一篇文档“docker 部署”部分,您应该知道我们在 docker 部署方式下默认提供了 es、redis、mysql 服务。但是在源码部署方式下,很难为您准备好这一切第三方服务,您需要选用云服务商提供的服务或者自建服务(安装 mysql、es、redis),这里不再详细叙述。对了,目前仅支持阿里云的 oss 服务(使用了对应的api)。 在获得了上述第三方服务之后,除 mysql 外,您无需对这些服务进行额外的初始化操作。当然,建立 oss bucket 这种操作就不提了。 mysql 需要提前使用gods-pen-server/sql/init.sql来初始化表结构和表数据。 mysql -h <host> -u<user> -p<password> < sql/init.sql # 请将<host> <user> <password> 换成实际值 至此,配置准备工作完成。 我们有三个项目,但是实际上,您无需逐一配置,我们已经提供了合适的默认配置,你只需要配置好第三方服务的信息即可,将信息填入gods-pen-server/config/config.dev.js gods-pen serve start 在当前目录(记得从 gods-pen-server 返回上一级)下运行gods-pen serve start,即可启动所有服务。 启动成功后访问http://127.0.0.1:8567注册用户、登陆系统 生产环境部署 生产环境的部署分两部分,前端静态资源的部署和 nodejs 服务的部署。 nodejs 服务 将 gods-pen-server 项目 clone 到服务器内,这一步您也可以通过 gods-pen 工具完成,类似上面开发环境的操作。 依赖安装好后,将第三方 es、redis、mysql、邮件、oss 服务信息配置到gods-pen-server/config/config.production.js内。 运行npm run serve启动服务,服务启动后,服务地址为http://127.0.0.1:7051/api 您应该使用 nginx 或其他服务器软件对 api 服务进行合理配置,使得外网能方便访问,比如将abc.com/api转发到 127.0.0.1:7051/api server { listen 80; server_name abc.com; # 您的实际 ip 或者域名 root /usr/share/nginx/html; # api 反向代理 location ^~ /api { proxy_pass http://127.0.0.1:7051; } } 前端项目部署 将 gods-pen-admin 和 gods-pen 项目 clone 下来,或者通过 gods-pen 工具也行。 安装依赖,然后在gods-pen-admin/src/config/production.js和gods-pen/src/config/production.js中添加配置API_PATH module.exports = { API_PATH: 'http://abc.com/api' # 配置为实际 nodejs api 服务外网可访问的路径 } 在当前目录(gods-pen-admin 的上一级)运行gods-pen serve build开始构建项目,完成后所有输出文件集中在当前目录下的 gods-pen-dist 下。 使用 nginx 或者其他服务器软件启动静态资源服务,将 gods-pen-dist 下所有文件复制到服务器软件指定目录下,您可以通过http://abc.com/admin访问到码良系统的入口页面 以下是一个 nginx 配置文件示例 server { listen 80; server_name abc.com; # 您的实际 ip 或者域名 root /usr/share/nginx/html; # 静态资源文件存放路径 # gzip gzip on; gzip_min_length 256; gzip_vary on; gzip_types *; # 所有静态资源及缓存 location ~* .*\.(jpg|gif|jpeg|css|png|js|wasm) { expires 10d; } # view路径,即渲染器,需要开启 history 模式 location ~* ^\/view\/[a-zA-Z0-9]+(\/|\?.*|)$ { index index.html; try_files $uri $uri/ /view/index.html; } # api 反向代理 location ^~ /api { proxy_pass http://godspen:7051; } } troubleshooting 拉取代码失败 由于一些众所周知的原因,github 的服务在某些时间某些网络环境下是不稳定的,如果出现了代码拉取失败的情况,请为你的命令行环境设置代理后再运行gods-pen serve fetch 安装依赖失败 这是由于缺少 c++ 编译环境造成部分 npm包编译失败,则通常发生在 window 系统上,您可以尝试全局安装 windows-build-tools windows-build-tools 是一个 npm 包,可以一键安装 c++ 编译所需的 python27、Visual Studio、C++ Build Tool 等。 Both installations are conflict-free, meaning that they do not mess with existing installations of Visual Studio, C++ Build Tools, or Python 另外上述问题在 python2 命令不可用时也会发生,如果您的机器没有安装 python 或者只安装了 python3 时,请安装 python27,或使用 pyenv 将 python 版本切换至 python2

优秀的个人博客,低调大师

Spring Cloud Gateway 扩展支持多版本控制及灰度发布

灰度发布 什么是灰度发布,概念请参考,我们来简单的通过下图来看下,通俗的讲: 为了保证服务升级过程的平滑过渡提高客户体验,会一部分用户 一部分用户递进更新,这样生产中会同时出现多个版本的客户端,为了保证多个版本客户端的可用需要对应的多个版本的服务端版本。灰度发布就是通过一定策略保证 多个版本客户端、服务端间能够正确对应。 所谓灰度发布,即某个服务存在多个实例时,并且实例版本间的版本并不一致,通过 实现方案 nginx + lua (openresty) Netflix Zuul 只需要自定义ribbon 的断言即可,核心是通过TTL 获取上下请求header中的版本号 @Slf4j public class MetadataCanaryRuleHandler extends ZoneAvoidanceRule { @Override public AbstractServerPredicate getPredicate() { return new AbstractServerPredicate() { @Override public boolean apply(PredicateKey predicateKey) { String targetVersion = RibbonVersionHolder.getContext(); RibbonVersionHolder.clearContext(); if (StrUtil.isBlank(targetVersion)) { log.debug("客户端未配置目标版本直接路由"); return true; } DiscoveryEnabledServer server = (DiscoveryEnabledServer) predicateKey.getServer(); final Map<String, String> metadata = server.getInstanceInfo().getMetadata(); if (StrUtil.isBlank(metadata.get(SecurityConstants.VERSION))) { log.debug("当前微服务{} 未配置版本直接路由"); return true; } if (metadata.get(SecurityConstants.VERSION).equals(targetVersion)) { return true; } else { log.debug("当前微服务{} 版本为{},目标版本{} 匹配失败", server.getInstanceInfo().getAppName() , metadata.get(SecurityConstants.VERSION), targetVersion); return false; } } }; } } 维护请求中的版本号 public class RibbonVersionHolder { private static final ThreadLocal<String> context = new TransmittableThreadLocal<>(); public static String getContext() { return context.get(); } public static void setContext(String value) { context.set(value); } public static void clearContext() { context.remove(); } } Spring Cloud Gateway 中实现 第一反应,参考zuul 的实现,自定义断言,然后从上下中获取版本信息即可。但由于 spring cloud gateway 是基于webflux 的反应式编程,所以传统的TTL或者 RequestContextHolder 都不能正确的维护上下文请求。 先来看 spring clou的 gateway 默认的lb 策略实现 LoadBalancerClientFilter public class LoadBalancerClientFilter implements GlobalFilter, Ordered { @Override public int getOrder() { return LOAD_BALANCER_CLIENT_FILTER_ORDER; } @Override @SuppressWarnings("Duplicates") public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange); } protected ServiceInstance choose(ServerWebExchange exchange) { return loadBalancer.choose( ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost()); } } 我们只需要重写 choose 方法,把上下文请求传递到路由断言中即可,如下 @Override protected ServiceInstance choose(ServerWebExchange exchange) { HttpHeaders headers = exchange.getRequest().getHeaders(); return loadBalancer.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(), headers); } 然后在路由断言中通过 PredicateKey获取到即可 public abstract class AbstractDiscoveryEnabledPredicate extends AbstractServerPredicate { /** * {@inheritDoc} */ @Override public boolean apply(@Nullable PredicateKey input) { return input != null && input.getServer() instanceof NacosServer && apply((NacosServer) input.getServer(), (HttpHeaders) input.getLoadBalancerKey()); } } 最后根据版本来计算 public class GrayMetadataAwarePredicate extends AbstractDiscoveryEnabledPredicate { @Override protected boolean apply(NacosServer server, HttpHeaders headers) { PigxRibbonRuleProperties ribbonProperties = SpringContextHolder.getBean(PigxRibbonRuleProperties.class); if (!ribbonProperties.isGrayEnabled()) { log.debug("gray closed,GrayMetadataAwarePredicate return true"); return true; } final Map<String, String> metadata = server.getMetadata(); String version = metadata.get(CommonConstants.VERSION); // 判断Nacos服务是否有版本标签 if (StrUtil.isBlank(version)) { log.debug("nacos server tag is blank ,GrayMetadataAwarePredicate return true"); return true; } // 判断请求中是否有版本 String target = headers.getFirst(CommonConstants.VERSION); if (StrUtil.isBlank(target)) { log.debug("request headers version is blank,GrayMetadataAwarePredicate return true"); return true; } log.debug("请求版本:{} ,当前服务版本:{}", target, version); return target.equals(version); } } 整合nacos 结合nacos的动态配置可以非常方便的实现灰度

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册