java多线程设计模式-WorkerPattern
- 格式:doc
- 大小:81.00 KB
- 文档页数:24
Java架构师必备知识点(高级程序员教程)2019年3月一、并发编程1.线程安全:当多个线程访问某一个类(对象)时这个类始终都能表现出正确的行为,那么这个类(对象和方法)就是线程安全的。
2.synchronized:可以在任意对象以及方法上加锁,而加锁的这段代码称为"互斥区"或者"临界区"。
一个线程想要执行synchronized修饰的方法里的内容,首先是尝试获得锁,如果拿到锁,执行synchronized方法体里面的内容如果拿不到那么这个线程会不断的尝试获得这把锁,直到拿到为止,而且是多个线程去竞争这把锁。
3.多个线程多个锁:多个线程,每个线程都将可以拿到自己指定的锁,分别获得锁之后,执行synchronized方法体的内容,关键字synchronized获得的锁都是对象锁,而不是把一段代码(方法)当做锁,在静态方法上机上synchronized获得的锁为类级别的锁,表示锁定类。
4.对象锁的同步和异步:同步synchronized:同步就是共享,同步的目的是为了线程安全,对于线程安全需要满足两个特性:原子性(同步)、可见性。
异步asynchronized:异步就是独立,相互之间不受任何制约。
5.脏读:对于对象的同步和异步方法,我们在设计程序的时候,一定要考虑问题的整体,不然就会出现数据不一致错误,很经典的错误就是脏读(dityread)。
在我们对一个对象的方法加锁的时候,需要考虑业务的整体性,即为setValue和getValue方法同时加锁synchronized同步关键字保证(service)业务逻辑层的原子性,不然会出现业务逻辑错误。
6.synchronized锁重入:关键字synchronized拥有重入锁的功能,也就是在使用synchronized时,当一个线程得到一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。
7.出现异常,锁自动释放:对于web应用程序,异常释放锁的情况,如果不及时处理,很可能对应用程序业务逻辑产生严重的错误。
《图解Java多线程设计模式》学习笔记(⼀)Java线程⼀、何谓线程1. 单线程程序处理流程始终如⼀条线某⼀时间点执⾏的处理只有⼀个正在执⾏程序的主体称为线程2. 多线程程序多个线程组成的程序称为多线程程序public class MyThread extends Thread{public void run(){for (int i = 0; i < 10000; i++) {System.out.println("Nice!");}}}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();// 注意要调⽤start,run⽅法可以调⽤,但不会开启新县城thread.start();for (int i = 0; i < 10000; i++) {System.out.println("Good!");}}}结果是交叉输出概念:顺序:多个操作依次处理并⾏:多个操作同时处理并发:将⼀个操作分成多个部分并允许⽆序处理⼆、线程的启动继承Thread,重写run⽅法public class PrintThread extends Thread {private String message;PrintThread(String message) {this.message = message;}public void run() {for (int i = 0; i < 10000; i++) {System.out.println(message);}}}public class Main {public static void main(String[] args) {new PrintThread("Good!").start();}}实现Runnable接⼝,实现run⽅法public class Printer implements Runnable {private String message;Printer(String message) {this.message = message;}@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(message);}}}new Thread(new Printer("Nice!")).start();Thread本⾝实现了Runnable接⼝,且有run⽅法,⽅法体为空。
Java多线程之实现多线程的三种⽅法⼀、创建多线程的⽅法1.继承Thread类类 Thread的类头为:public class Thread implement runnable继承Thread类,并重写Thread中的run⽅法例如:1package com.dragon.test;23public class MyThread extends Thread{4 @Override5 public void run(){6 System.out.println("创建多线程⽅法⼀");7 }8 public static void main(String[] args) {9 MyThread thread=new MyThread();10 thread.start();11 System.out.println("运⾏结束");12 }1314 }运⾏结果:这说明在使⽤多线程技术时,代码的运⾏结果与代码执⾏顺序后调⽤代码的顺序是⽆关的即线程是⼀个⼦任务,CPU以随机的时间来调⽤线程中的⽅法。
注意:1.不能多次调⽤Thread中的start()⽅法,否则会抛出IllegalThreadStateException异常。
2.启动线程的⽅法不是run()⽅法⽽是start⽅法,如果调⽤的是run()⽅法就是同步的,并不能异步执⾏。
3.执⾏start()⽅法的顺序不代表线程启动的顺序,即并不是说,越早调⽤某个线程的start()⽅法,它就能越早的执⾏其中的run()⽅法。
2.实现Runnable接⼝实现Runnable接⼝,重写run()⽅法例如:1package com.dragon.test;23public class MyThread implements Runnable{4 @Override5public void run(){6 System.out.println("创建多线程⽅法⼆");7 }8public static void main(String[] args) {9 MyThread thread=new MyThread();10 Thread t=new Thread(thread);11 t.start();12 System.out.println("运⾏结束");13 }1415 }运⾏结果与上述第⼀种的运⾏结果没有什么特殊之处因为Thread类也实现了Runnable接⼝,所以Thread中的构造函数就可以传⼊⼀个Runnable接⼝的对象,也可以传⼊⼀个Thread类的对象 3.实现Callable接⼝实现Callable接⼝,重写call()⽅法例如:package com.dragon.test;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class MyThread implements Callable<string>{public static void main(String[] args) {ExecutorService threadPool=Executors.newSingleThreadExecutor();//启动多线程Future<string> future=threadPool.submit(new MyThread());try{System.out.println("waiting thread to finish");System.out.println(future.get());}catch(Exception e){e.printStackTrace();}}@Overridepublic String call() throws Exception {// TODO Auto-generated method stubreturn "创建多线程⽅法三";}}</string></string> 运⾏结果:Callable接⼝是属于Executor,对⽐与Runnable接⼝功能的区别是:(1).Callable可以在任务结束后提供⼀个返回值,Runnable没有这个功能(2).Callable中的call()⽅法可以抛出异常,⽽Runnable的run()⽅法不能抛出异常(3).运⾏Callable可以拿到⼀个Future对象,Future独享表⽰异步计算的结果,它提供了检查计算是否完成的⽅法。
Java多线程用法什么是多线程在计算机科学中,线程(Thread)是指程序执行的最小单元。
一个进程可以包含多个线程,每个线程可以并行地执行不同的任务。
多线程的概念出现是为了提高程序的并发性和响应性。
在Java中,可以使用多种方式实现多线程,如继承Thread类、实现Runnable接口、使用Executor框架等。
本文将介绍Java中常用的多线程用法。
继承Thread类Java中通过继承Thread类来创建线程。
下面是一个简单的例子:public class MyThread extends Thread {public void run() {// 线程执行的代码}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}}在上面的例子中,我们创建了一个名为MyThread的类,继承自Thread类,并重写了run方法。
run方法定义了线程要执行的代码逻辑。
在main方法中,我们创建了一个MyThread对象,并调用其start方法来启动线程。
实现Runnable接口除了继承Thread类外,还可以通过实现Runnable接口来创建线程。
下面是一个示例:public class MyRunnable implements Runnable {public void run() {// 线程执行的代码}public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}}在上面的例子中,我们定义了一个名为MyRunnable的类,实现了Runnable接口,并重写了run方法。
在main方法中,我们创建了一个Thread对象,并将MyRunnable对象作为参数传递给Thread的构造函数来创建线程。
JAVA常用设计模式详解大全设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
它是将设计经验系统化的产物,目的是提高代码的可复用性、可维护性和可扩展性。
常用的设计模式主要分为三类:创建型模式、结构型模式和行为型模式。
下面将详细介绍每一种模式及其使用方式。
一、创建型模式1. 单例模式(Singleton Pattern)单例模式用于确保一个类只有一个实例,并提供全局访问方法。
常用于线程池、缓存和日志等场景。
2. 工厂模式(Factory Pattern)工厂模式用于根据不同的输入参数创建不同的实例。
常用于对象的创建过程复杂或者需要隐藏创建逻辑的场景。
3. 抽象工厂模式(Abstract Factory Pattern)抽象工厂模式用于创建一系列相关或依赖的对象,且客户端无需关心具体的实现类。
常用于创建多个产品族的场景。
4. 建造者模式(Builder Pattern)建造者模式用于将一个复杂对象的创建过程和其表示分离,以使同样的创建过程可以创建不同的表示。
常用于构建参数较多的对象。
5. 原型模式(Prototype Pattern)原型模式用于创建对象的克隆,避免了通过new关键字创建对象的性能开销。
常用于创建对象的过程耗费资源较多的场景。
二、结构型模式1. 适配器模式(Adapter Pattern)适配器模式用于将一个类的接口转换为客户端所期望的接口。
常用于不兼容接口之间的适配。
2. 装饰器模式(Decorator Pattern)装饰器模式用于动态地给一个对象添加额外的功能。
常用于对原有类的功能进行扩展或包装。
3. 代理模式(Proxy Pattern)代理模式用于控制对其他对象的访问。
常用于远程代理、虚拟代理、保护代理等场景。
4. 外观模式(Facade Pattern)外观模式用于提供一个简化的接口,隐藏一系列复杂的子系统。
常用于简化复杂系统的接口调用过程。
Java多线程编程详解线程的同步由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。
Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。
由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明synchronized 方法。
如:Java代码1.public synchronized void accessVal(int newVal);synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。
这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。
java中的多线程的实现⽣产者消费者模式丈夫类:往银⾏账户⾥存钱,存款[0~10000)的随机数,2秒存⼀次妻⼦类:从银⾏账户⾥取钱,取款[0~10000)的随机数,2秒取⼀次,如果余额不⾜,等到丈夫存了钱,再取public class TestAccount { public static void main(String[] args) { Account account = new Account(); account.setAccount("116854398"); account.setBalance(10); Thread t1 = new Wife(account, TestAccount.class); Thread t2 = new Husband(account, TestAccount.class); t1.start(); t2.start(); }}import java.util.Random;public class Wife extends Thread{ private Account account; private Object lock; public Wife(Account account, Object lock) { this.account = account; this.lock = lock; } public void run() { while (true) { synchronized (lock) { Random random = new Random(); int withDraw = random.nextInt(10000); if (account.getBalance() >= withDraw) { account.setBalance(account.getBalance() - withDraw); System.out.println("妻⼦取了:" + withDraw + "元"); System.out.println(account); try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } else { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }}import java.util.Random;public class Husband extends Thread{ private Account account; private Object lock; public Husband(Account account, Object lock) { this.account = account; this.lock = lock; } public void run() { while(true) { synchronized (lock) { Random random = new Random(); int exists = random.nextInt(10000); account.setBalance(account.getBalance() + exists); System.out.println("丈夫存了:" + exists + "元"); System.out.println(account); try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } lock.notify(); } } }}。
Java中常⽤的设计模式23种JAVA设计模式项⽬实战教程java数据结构算法Java中常⽤的设计模式 23种JAVA设计模式项⽬实战教程java数据结构算法58套Java⾼级架构师视频教程,微服务,⾼并发,分布式,⾼可⽤,⾼性能,集群架构,设计模式,数据结构,中间件,并发编程,虚拟机,⾼可扩展,服务器,数据库,性能调优,负载均衡,安全架构,全⽂检索,权限管理Spring Boot,Spring Cloud⼤型分布式综合电商项⽬实战等视频教程JAVA⾼级架构师技术包含:JAVA架构设计,系统架构,缓存架构,分布式架构,安全架构,微服务,⾼并发,⾼可⽤,⾼可扩展,⾼性能,集群搭建,设计模式,数据结构,中间件,并发编程,JVM虚拟机,性能调优,负载均衡,单点登录,⽇志分析,全⽂检索,任务调度,权限管理,⼯作流,⽹络编程,脚本编程,分布式事务,分库分表,团队协作,持续集成,⾃动化部署,服务器,数据库,图形数据库,项⽬实战,SSM框架,SpringBoot,SpringCloud,Maven,Mybatis,Docker,K8S,Devops,Jenkins,Elasticsearch,Nginx,Tomcat,RabbitMQ,RocketMQ,ActiveMQ,Kafka,Dubbo,Solr,SSO,CAS,OA,Ehcache,Memcached,Activiti,Quartz,Shiro ,Git,Netty ,NIO,Linux,Shell,IDEA,Spring,Springmvc,SpringSecurity,SpringData,VueJS,RectJS,AngularJS,NodeJS,Hadoop,Hbase,Spark,HttpClient,Json,Nosql,Mysql,Redis,MongoDB,Zookeeper,Mycat,Oracle,健康项⽬实战,秒杀系统实战,电商项⽬实战,在线教育实战,P2P⾦融项⽬实战,⼤型分布式综合电商项⽬实战等视频教程......58套精品教程介绍:1、58套精品是掌柜最近整理出的最新教程,都是当下最⽕的技术,最⽕的课程,也是全⽹教程的精品;2、58套资源包含:全套完整⾼清视频、完整源码、配套⽂档;3、知识也是需要投资的,有投⼊才会有产出(保证投⼊产出⽐是⼏百上千倍),如果有⼼的朋友会发现,⾝边投资知识的⼤都是技术经理或者项⽬经理,⼯资⼀般相对于不投资的也要⾼出很多;总⽬录:58套JAVA⾼级架构师,微服务架构,亿级⾼并发,分布式架构,源码剖析系列,项⽬实战,设计模式实战,数据结构与算法,消息中间件,并发编程多线程,服务器系列,数据库,分布式事务,⼤型分布式综合电商项⽬实战视频教程第⼀套:01.【⾼并发课】亿级⾼并发⼤型电商详情页系统的⾼性能与⾼可⽤缓存架构实战视频教程第⼆套:02.【微服务课】微服务架构实战160讲.8⼤核⼼模块精讲.打通架构师进阶之路视频教程第三套:03.【项⽬实战】微服务电商系统从设计到实现全流程讲解基于SpringCloud视频教程第四套:04.【项⽬实战】微服务架构⼴告设计系统实战基于SpringCloud+Kafka+Mysql视频教程第五套:【项⽬实战】精讲SpringBoot2.0互联⽹⾦融理财项⽬实战,开发实战与原理分析视频教程(3套)第01套【主流框架】SpringBoot2.0全新系列精通到实战史上最全的完整版视频教程第02套【主流框架】Spring Boot实战与原理分析视频课程第03套【主流框架】SpringBoot2.0互联⽹⾦融理财系统综合项⽬实战视频课程第六套:06.【微服务课】精通SpringBoot Cloud微服务框架,实战案例与源码剖析视频教程(2套)第01套.Spring Cloud微服务最新技术⼊门到精通视频教程第02套.精通Spring Boot Cloud使⽤并理解框架的原理与底层运作机制视频教程第七套:07.【源码解析】深度剖析Spring Spring5 Mybatis Tomcat源码系列底层框架解析视频教程第⼋套:08.【项⽬实战】微服务容器化综合实践Docker+Kubernetes践⾏DevOps理念 k8s部署落地(3套)第01套:Docker+Kubernetes(k8s)微服务容器化及多技术综合实践视频教程第02套:深⼊系统学习Docker容器技术,实践DevOps理念视频教程第03套:Kubernetes(k8s)落地全程实践企业级应⽤实践从部署到核⼼应⽤视频教程第九套:09.【项⽬实战】从⽆到有搭建中⼩型互联⽹公司后台服务架构与运维架构视频课程第⼗套:10.【设计模式】精讲Java23种设计模式源码分析+内存分析+编程思想+Debug⽅式视频教程第⼗⼀套:11.【项⽬实战】设计模式综合项⽬(实战)设计模式综合应⽤的实战案例视频教程第⼗⼆套:12.【项⽬实战】软件系统功能设计(实战)训练(6个设计案例)视频教程第⼗三套:13.【数据结构】恋上数据结构与算法,程序员修炼编程内功(数组,栈,队列,链表,递归,排序,堆等)第⼗四套:14.【⾼级进阶】深度解析Spring5新特性,Java8~11新特性原理与实践,⾼级进阶实战视频教程第01套:Java8新特性原理,⾼级进阶实战视频教程第02套:Java9、10、11新特性全套精讲视频教程第03套:深⼊浅出spring原理与实践视频课程第04套:Spring5新特性及应⽤举例精讲剖析视频教程第⼗五套:15.【项⽬实战】快速上⼿SSO单点登录开发与项⽬实战单点登录在集群开发的作⽤视频教程(2套)第01套【单点登录】SSO单点登录快速上⼿与项⽬实战视频教程第02套【单点登录】SSO单点登录开发与实战,单点登录在集群开发的作⽤视频教程第⼗六套:16.【⾼级架构】Java架构之消息中间件Kafka RabbitMQ RocketMQ ActiveMq精通实战(4套)01.【中间件】ActiveMq中间件基础到精通⾼级实战视频课程02.【中间件】JAVA-ACE架构师系列课程 Rocketmq03.【中间件】RabbitMQ中间件基础到精通,消息订阅视频课程04.【中间件】Kafka分布式消息中间节原理剖析及实战演练视频课程第⼗七套:17.【项⽬实战】企业⽇志平台⽣产案例实战,⽇志分析之ELK stack实战视频教程第⼗⼋套:18.【⾼级进阶】顶尖⾼⼿系列Elasticsearch快速上⼿篇+⾼⼿进阶篇视频课程第⼗九套:19.【项⽬实战】基于Activiti6.X⼯作流进阶与项⽬实战,Activiti整合Drools视频课程第⼆⼗套:20.【任务调度】Spring+Quartz的分布式任务调度及源码解析视频课程第⼆⼗⼀套:21.【系统学习】Java架构之Shiro权限管理权限设计实现项⽬案例,与Springboot整合教程(3套)第01套.SpringBoot与Shiro整合-权限管理实战视频第02套.Shiro基础到精通,原理与架构视频课程第03套.Apache Shiro权限框架实战+项⽬案例+权限设计实现视频课程第⼆⼗⼆套:22.【系统学习】深⼊学习Zookeeper分布式系统开发实战视频课程第⼆⼗三套:23.【分布式】Dubbo第三⽅⽀付项⽬的系统架构实战视频教程第⼆⼗四套:24.【微服务】基于⽀付系统场景的微服务架构的分布式事务解决⽅案视频课程第⼆⼗五套:25.【项⽬实战】实战技能Linux100讲全⽅位实战讲解视频教程第⼆⼗六套:26.【linux精讲】Shell脚本编程⼤量企业级实例带你全⾯掌握六⼤技术点视频教程第⼆⼗七套:27.【⾼级进阶】⾼并发多线程实训营-Java多线程编程三个阶进阶实战视频教程第⼆⼗⼋套:28.【⾼级架构】架构之⾼并发系统架构实战⽅案 Java⾼并发解决⽅案与并发编程教程第⼆⼗九套:29.【⾼级进阶】深⼊Java并发编程原理与实战线程安全+锁原理+同步容器+实战讲解视频教程第三⼗套:30.【分布式】分布式事务框架Myth+Raincat+Tcc源码解析视频教程第三⼗⼀套:31.【分布式】分布式常见问题解决⽅案,分布式事务与锁,缓存实战解决⽅案视频教程第三⼗⼆套:32.【分布式】解决分布式事务数据⼀致性开发与实践分布式事务实现视频教程第三⼗三套:33.【分布式】分布式集群部署实战,分布式存储缓存协调调度视频教程第三⼗四套:34.【性能优化】深⼊JAVA虚拟机,JVM内核-原理,诊断与优化+内存模型+虚拟机原理视频教程第三⼗五套:35.【性能优化】架构⼤⽜带你学习MySql,Nginx,Tomcat,JVM性能调优系列专题视频教程第三⼗六套:36.【性能优化】深⼊JAVA程序性能调优视频(阿姆达尔定律、缓存组件、并⾏开发、线程池、JVM调优)第三⼗七套:37.【⾼级进阶】全⾯深⼊Mysql数据库系统优化+查询优化,Mysql⼤型分布式集群,从⼩⽩到⼤神(3套)第01套:全⾯深⼊Mysql数据库优化查询优化mysql⾼级第02套【数据库】MySQL⾼级⼤型分布式集群,主从复制,负载均衡,数据库中间件视频课程第03套:Mysql从⼩⽩到⼤神视频教程第三⼗⼋套:38.【⾼级进阶】深⼊进阶Oracle DBA性能优化+⾼可⽤+海量数据库设计视频课程(2套)第三⼗九套:39.【项⽬实战】企业级开发与运维Redis从⼊门到项⽬实战视频教程第四⼗套:40.【项⽬实战】精通MongoDB4.0从⼊门到实践,掌握NoSQL数据库企业主流解决⽅案视频教程第四⼗⼀套:41.【⾼级架构】Java架构之Mycat实现mysql⾼可⽤集群,分布库分表中间件视频教程第四⼗⼆套:42.【数据库】图形数据库之王 Neo4j从⼊门到精通视频教程第四⼗三套:43.【⾼级进阶】企业级Nginx核⼼知识,百万并发下的Nginx性能优化之道视频教程。
java中的多线程在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable 接口。
对于直接继承Thread的类来说,代码大致框架是:先看一个简单的例子:【运行结果】:A运行0 A运行1 A运行2 A运行3 A运行4 B运行0 B运行1 B运行 2 B运行3 B运行4我们会发现这些都是顺序执行的,说明我们的调用方法不对,应该调用的是start()方法。
当我们把上面的主函数修改为如下所示的时候:然后运行程序,输出的可能的结果如下:A运行 0 B运行 0 B运行 1 B运行 2 B运行 3 B运行 4 A运行 1 A运行 2 A运行 3 A运行 4因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的,呵呵。
注意:虽然我们在这里调用的是start()方法,但是实际上调用的还是run()方法的主体。
那么:为什么我们不能直接调用run()方法呢?我的理解是:线程的运行需要本地操作系统的支持。
如果你查看start的源代码的时候,会发现:注意我用红色加粗的那一条语句,说明此处调用的是start0()。
并且这个这个方法用了native关键字,次关键字表示调用本地操作系统的函数。
因为多线程的实现需要本地操作系统的支持。
但是start方法重复调用的话,会出现ng.IllegalThreadStateException异常。
通过实现Runnable接口:大致框架是:来先看一个小例子吧:【可能的运行结果】:线程A运行 0 线程B运行 0 线程B运行 1 线程B运行 2线程B运行 3 线程B运行 4 线程A运行 1线程A运行 2 线程A运行 3 线程A运行 4关于选择继承Thread还是实现Runnable接口?其实Thread也是实现Runnable接口的:其实Thread中的run方法调用的是Runnable接口的run方法。
不知道大家发现没有,T hread和Runnable都实现了run方法,这种操作模式其实就是代理模式。
Java中的设计模式和架构模式详解设计模式和架构模式是软件开发中非常重要的概念,它们可以帮助开发人员更好地设计和构建高质量的软件系统。
在Java中,设计模式和架构模式被广泛应用,许多经典的设计模式和架构模式都有对应的Java实现。
一、设计模式设计模式是针对软件设计中常见问题的解决方案的模板。
它们提供了一种通用的设计方法,可以帮助开发人员更好地组织和管理代码。
在Java中,最常用的设计模式包括:1.工厂模式(Factory Pattern):工厂模式是一种创建型设计模式,用于创建对象而不暴露创建逻辑。
它可以帮助我们将对象的创建和使用解耦,使系统更加灵活和可维护。
2.单例模式(Singleton Pattern):单例模式是一种创建型设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。
在Java中,单例模式通常通过私有化构造函数、静态变量和静态方法实现。
3.观察者模式(Observer Pattern):观察者模式是一种行为设计模式,用于实现对象之间的一对多依赖关系。
在Java中,观察者模式通常通过Java内置的Observer接口和Observable类实现。
4.策略模式(Strategy Pattern):策略模式是一种行为设计模式,用于定义一系列算法,并将每个算法封装起来,使它们可以互相替换。
在Java中,策略模式常常通过接口和实现类实现。
5.适配器模式(Adapter Pattern):适配器模式是一种结构设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。
在Java中,适配器模式通常通过接口实现或类继承实现。
以上只是部分常见的设计模式,在Java中还有许多其他设计模式,每种设计模式都有其特定的使用场景和优缺点,开发人员可以根据具体情况选择合适的设计模式来解决问题。
二、架构模式架构模式是指软件系统整体结构的模式,它可以指导系统的整体设计和组织。
在Java中,常见的架构模式包括:1.模型-视图-控制器模式(Model-View-Controller,MVC):MVC 是一种使用最广泛的架构模式,它将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个部分,分别负责数据处理、用户界面和业务逻辑。
多线程经典实例java语言已经内置了多线程支持,所有实现Runnable接口的类都可被启动一个新线程,新线程会执行该实例的run()方法,当run()方法执行完毕后,线程就结束了。
一旦一个线程执行完毕,这个实例就不能再重新启动,只能重新生成一个新实例,再启动一个新线程。
Thread类是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法:Thread t = new Thread();t.start();start()方法是一个native方法,它将启动一个新线程,并执行run()方法。
Thread类默认的run()方法什么也不做就退出了。
注意:直接调用run()方法并不会启动一个新线程,它和调用一个普通的java方法没有什么区别。
因此,有两个方法可以实现自己的线程:方法1:自己的类extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
例如:public class MyThread extends Thread {public run() {System.out.println("MyThread.run()");}}在合适的地方启动线程:new MyThread().start();方法2:如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口:public class MyThread extends OtherClass implements Runnable {public run() {System.out.println("MyThread.run()");}}为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:MyThread myt = new MyThread();Thread t = new Thread(myt);t.start();事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:public void run() {if (target != null) {target.run();}}线程还有一些Name, ThreadGroup, isDaemon等设置,由于和线程设计模式关联很少,这里就不多说了。
由于同一进程内的多个线程共享内存空间,在Java中,就是共享实例,当多个线程试图同时修改某个实例的内容时,就会造成冲突,因此,线程必须实现共享互斥,使多线程同步。
最简单的同步是将一个方法标记为synchronized,对同一个实例来说,任一时刻只能有一个synchronized方法在执行。
当一个方法正在执行某个synchronized方法时,其他线程如果想要执行这个实例的任意一个synchronized方法,都必须等待当前执行 synchronized方法的线程退出此方法后,才能依次执行。
但是,非synchronized方法不受影响,不管当前有没有执行synchronized方法,非synchronized 方法都可以被多个线程同时执行。
此外,必须注意,只有同一实例的synchronized方法同一时间只能被一个线程执行,不同实例的synchronized方法是可以并发的。
例如,class A定义了synchronized方法sync(),则不同实例a1.sync()和a2.sync()可以同时由两个线程来执行。
多线程同步的实现最终依赖锁机制。
我们可以想象某一共享资源是一间屋子,每个人都是一个线程。
当A希望进入房间时,他必须获得门锁,一旦A获得门锁,他进去后就立刻将门锁上,于是B,C,D...就不得不在门外等待,直到A释放锁出来后,B,C,D...中的某一人抢到了该锁(具体抢法依赖于 JVM的实现,可以先到先得,也可以随机挑选),然后进屋又将门锁上。
这样,任一时刻最多有一人在屋内(使用共享资源)。
Java语言规范内置了对多线程的支持。
对于Java程序来说,每一个对象实例都有一把“锁”,一旦某个线程获得了该锁,别的线程如果希望获得该锁,只能等待这个线程释放锁之后。
获得锁的方法只有一个,就是synchronized关键字。
例如:public class SharedResource {private int count = 0;public int getCount() { return count; }public synchronized void setCount(int count) { this.count = count; }}同步方法public synchronized void setCount(int count) { this.count = count; } 事实上相当于:public void setCount(int count) {synchronized(this) { // 在此获得this锁this.count = count;} // 在此释放this锁}红色部分表示需要同步的代码段,该区域为“危险区域”,如果两个以上的线程同时执行,会引发冲突,因此,要更改SharedResource的内部状态,必须先获得SharedResource实例的锁。
退出synchronized块时,线程拥有的锁自动释放,于是,别的线程又可以获取该锁了。
为了提高性能,不一定要锁定this,例如,SharedResource有两个独立变化的变量:public class SharedResouce {private int a = 0;private int b = 0;public synchronized void setA(int a) { this.a = a; }public synchronized void setB(int b) { this.b = b; }}若同步整个方法,则setA()的时候无法setB(),setB()时无法setA()。
为了提高性能,可以使用不同对象的锁:public class SharedResouce {private int a = 0;private int b = 0;private Object sync_a = new Object();private Object sync_b = new Object();public void setA(int a) {synchronized(sync_a) {this.a = a;}}public synchronized void setB(int b) {synchronized(sync_b) {this.b = b;}}}通常,多线程之间需要协调工作。
例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程 downloadThread将该图片下载完毕。
如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了任务后,再通知displayThread“图片准备完毕,可以显示了”,这时,displayThread继续执行。
以上逻辑简单的说就是:如果条件不满足,则等待。
当条件满足时,等待该条件的线程将被唤醒。
在Java中,这个机制的实现依赖于wait/notify。
等待机制与锁机制是密切关联的。
例如:synchronized(obj) {while(!condition) {obj.wait();}obj.doSomething();}当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:synchronized(obj) {condition = true;obj.notify();}需要注意的概念是:# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
# 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
# obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。
直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
前面讲了wait/notify机制,Thread还有一个sleep()静态方法,它也能使线程暂停一段时间。
sleep与wait的不同点是: sleep并不释放锁,并且sleep的暂停和wait暂停是不一样的。
obj.wait会使线程进入obj对象的等待集合中并等待唤醒。
但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。
如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。
如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。
需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。
对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。
但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException。