问题场景一:
Web应用中,后台一般都分成几层,最常用的分法有控制层、业务逻辑层、数据持久层和表现层。一般情况下,我们都会把当前用户存放在HttpSession里面。怎么获取到当前用户的信息呢?首先,要获得HttpServletRequest对象,然后通过它的getSession()方法获取HttpSession对象,从而根据对应的Key值拿到用户信息。
现在我们提出一个新的要求,在控制层、业务逻辑层、数据持久层和表现层都能方便的获取到当前用户的信息。怎么实现呢?
想一想,发现了两种方法:
(1)控制层肯定可以拿到HttpServletRequest对象,所以控制层是可以获取到用户信息的,那么业务逻辑层、数据持久层和表现层怎么办呢?最直接的方法就是在上层调用下层的时候通过方法参数传下去。这样各个层的都能获得HttpServletRequest对象。那么就可以实现各层获取当前用户的信息了。
(2)新建一个类,类里面有一个静态Map,一开始的时候,将当前HttpServletRequest保存到这个类的Map中,问题是放进去后,我们凭什么拿出来呢?Map的key值放什么好呢?必须放一个到处都可以拿到的对象,并且可以表示我当前这个请求。我们想到了当前线程,Servlet容器对于每个请求都有一个线程来处理的,所以一个请求处理时间内,一个线程可以唯一标识一个请求。那么,我们就那当前线程对象作为Map的key值,value值为HttpServletRequest对象。这样我们再通过这个类的一个静态方法,传入当前线程对象从而获得HttpServletRequest对象,从而获取到当前用户的信息。
问题场景二:
一个请求的处理涉及几次数据库操作,假如这几次数据库操作都是针对同一个数据库用户的。正常情况下,JDBC执行的顺序是:
(1)获取一个数据库连接
(2)数据库操作1
(3)数据库操作2
(4)组装结果数据
(5)是释放连接回连接池
但是,很多封装好的持久层框架(比如Spring、Ibatis等)的执行顺序是这样的:
(1)获取一个数据库连接
(2)数据库操作1
(3)组装结果数据
(4)是释放连接回连接池
(5)获取一个数据库连接
(6)数据库操作2
(7)组装结果数据
(8)是释放连接回连接池
就第二种情况,两次的数据库操作是分开的,怎么保证两次数据库操作能在同一个事务里面,我们知道同一个事务的前提是两次操作的数据库连接要是同一个才行。所以怎么保证,一次请求的处理过程中,都在同一个事务中。说白了,就是怎么保证一次请求处理的过程中,拿到的数据库连接永远是同一个。
这个时候,我们就回想到,能不能跟场景一一样,让连接跟线程绑定,每次获取到的数据库连接都会是同一个。
线程变量实现
(1)自己动手实现:
public class ThreadVariable {
private static Map variableMap = new HashMap();
public static void addVariable(String variableName,String variableValue){
Map map = null;
Long threadId = Thread.currentThread().getId();
if(variableMap.containsKey(threadId)){
map = (Map)variableMap.get(threadId);
}
else{
map = new HashMap();
variableMap.put(threadId, map);
}
map.put(variableName, variableValue);
}
public static Object getVariable(String variableName) throws Exception{
Long threadId = Thread.currentThread().getId();
if(variableMap.containsKey(threadId)){
Map map = (Map)variableMap.get(threadId);
return map.get(variableName);
}
else{
throw new Exception("the variable [" + variableName + "] does not exist");
}
}
public static boolean removeVariable(String variableName){
try{
variableMap.remove(variableName);
return true;
}catch(Exception e){
return false;
}
}
}
(2)使用JDK本身支持的ThreadLocal对象
private static final ThreadLocal context = new ThreadLocal();
context.set("zhangsan");
Object object = context.get();
使用总结:
(1)解决多线程并发的资源共享问题,每一个线程提供一个独立的变量副本,从而隔离了多个线程对访问数据的冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。
注意:并不是所有使用同步的地方都可以改用线程变量的方式,因为有些数据是必须要保持全局的唯一、一致性的,这种情况下如果使用线程变量则会有多份不一致的副本。
(2)保证一个线程所涉及的各个层次的代码都可能访问到同一个线程的变量。
比如:怎么保证一次线程处理的数据库操作能够统一提交?事务的统一提交是有前提的,都使用同一个Connection对象。
对于多线程资源共享的问题,我们比较一下同步机制和线程变量的区别:
(1)同步机制采用了“以时间换空间”的方式:访问串行化,数据共享化。多个线程同时访问同一个资源需要排队等候。
(2)线程变量采用了“以空间换时间”的方式:访问并行化,为每一个线程都提供了一份变量。
分享到:
相关推荐
1. Java编程基础知识:变量、数据类型、控制流语句、函数、数组、链表、栈、队列、树等。 2. Java常用算法和数据结构:冒泡排序、选择排序、插入排序、链表、树等。 3. Java网络编程基础知识:TCP/IP协议、Socket...
【JAVA基础】JAVA多线程编程详解 Java多线程编程是Java开发中不可或缺的一部分,它允许多个任务在同一时间并发执行,提高了程序的效率和响应性。在Java中,线程是程序中的执行流,每个线程都有独立的执行控制,由...
这篇“Java基础知识总结(经典)”涵盖了Java开发中的核心概念和重要知识点,旨在为初学者和有经验的开发者提供一个全面的回顾。以下是主要的学习点: 1. **Java环境配置**:在开始编程之前,必须安装Java ...
### 并发编程基础知识,Java内存模型及多线程、volatile #### Java内存模型(JMM) Java内存模型(Java Memory Model, JMM)是Java并发编程的基础之一,它定义了一套规则来保证线程之间的数据可见性和一致性。当程序...
一、Java多线程基础 1. 创建线程: - 继承Thread类:创建一个新的类,继承自Thread类,重写其run()方法,然后创建该类的实例并调用start()方法。 - 实现Runnable接口:创建一个实现了Runnable接口的类,实现run()...
Java基础知识是学习Java编程语言的基石,涵盖了许多关键概念。以下是一些主要的Java基础知识知识点: 1. **数据类型**:Java分为基本数据类型(如int, double, boolean等)和引用数据类型(如类、接口和数组)。...
在Java中,多线程是一种非常重要的编程概念,...这些面试题涵盖了Java多线程编程的基础知识、同步机制、线程间通信以及并发集合类等多个方面。在准备面试时,对这些问题进行深入理解和准备,能够有效提升面试的成功率。
Java 基础知识总结 Java 是一种广泛使用的编程语言,由 Sun 公司的 James Gosling 等人于 1991 年开始开发。Java 有三种技术架构:JavaEE、JavaSE 和 JavaME。JavaSE 是桌面应用程序的开发基础,JavaEE 是企业环境...
这份"Java基础知识PPT"涵盖了Java学习的核心概念,对于初学者来说是一份非常宝贵的资料。 1. **Java简介**:Java最初由James Gosling等人开发,其设计理念是“一次编写,到处运行”。它基于C++,但简化了语法,去除...
本教程将深入讲解Java线程的基础知识,帮助你掌握多线程编程的核心技能。 1. **线程的创建** - **继承Thread类**:创建一个新的类,该类继承自Thread类,然后重写它的`run()`方法。通过创建此类的实例并调用其`...
本篇知识点将详细解读Java线程的基础知识,包括线程的定义、它在多线程编程中的作用、线程间通信的基本方法、线程的优劣势以及如何在Java中创建和管理线程。 首先,线程可以理解为在进程内独立执行的路径,它拥有...
1. **线程基础**:首先,书中可能会介绍线程的基本概念,包括进程与线程的区别,以及Java中创建线程的两种方式:继承Thread类和实现Runnable接口。此外,还会讲解线程的状态(新建、可运行、运行、阻塞和死亡)及其...
Java 基础知识文档详述了Java编程语言...以上只是Java基础知识的一部分,深入学习还需要涵盖多线程、集合框架、网络编程、反射、注解等更多内容。对于初学者,理解并掌握这些基础知识是构建坚实Java编程技能的第一步。
Java基础知识总结涵盖了Java程序设计语言的核心概念和常用知识点。在详细学习和总结这些知识点之前,首先需要对Java有一个整体的认识。Java是一种面向对象的编程语言,它具有跨平台的特性,即“一次编写,到处运行”...
【Java系列文章】Java 基础知识涵盖了Java开发中的核心概念和常见问题,以下是针对这些知识点的详细解析: ...以上就是Java基础知识的详细解读,涵盖了从基础到进阶的多个方面,有助于深入理解Java编程的核心概念。
在Java中,多线程主要涉及到以下几个关键知识点: 1. **进程与线程**: - **进程**:是操作系统分配资源的基本单位,一个进程可以包含一个或多个线程。 - **线程**:是进程内的执行单元,共享进程的内存空间,...
1. **基础语法**:包括变量、数据类型(如整型、浮点型、字符型、布尔型以及引用类型)、运算符(算术、关系、逻辑、位、赋值等)、流程控制(if语句、switch语句、for、while、do-while循环)、方法定义与调用。...
Java 基础知识点总结 一、Java 概述 * Java 语言的出现背景:1991 年 Sun 公司的 James Gosling 等人开始开发 Oak 语言,后更名为 Java 语言。 * Java 语言的特点:平台无关性、简单、面向对象、健壮性、安全性、...
### Java线程基础 在Java语言中,线程是程序执行流的基本单元。一个标准的Java应用程序至少会有一个线程,即主线程,用于执行程序的主要逻辑。通过创建多个线程,可以实现并发执行任务,提高程序的运行效率和响应...