您的位置:首页 > 编程语言 > Java开发

spring的线程流程

2016-02-25 17:49 387 查看
1.什么范围属于同一线程?

书286页说到

从接收请求到返回响应所经过的所有程序调用都属于同一线程。

书120页说到

因为web容器的特性,一个http请求一般情况下对应一个独立的线程

一个请求线程里只有一个连接,一个连接对应一个事务,该事务根据事务传播行为由多个业务组成,一个业务对应多个dao,多个dao共享一个连接,第一个dao创建连接并放进threadlocal里,其他dao直接使用该连接。

书287页说到,同个事务多个dao共享一个连接,不同线程使用某个dao类时,只使用线程相关的连接.

以下内容出自链接:http://blog.csdn.net/initphp/article/details/8259391

java的线程

假如我们做的是web程序,那么http的每次请求都会在一个java进程中启动,并且这个程序会生成一个线程去跑。所以java写的web程序是多线程的。我们可以通过Thread.currentThread().getName();方法查看Http每次请求的线程名称。

例如,我们在Spring中创建一个测试的Action。访问地址:http://127.0.0.1:8090/test/test/

代码如下:

[java] view
plain copy

print?

package com.xxx.www.test.web;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.servlet.ModelAndView;

import com.alios.www.test.domain.GuestbookDo;

import com.alios.www.test.service.GuestbookService;

import com.alios.www.test.service.TestService;

/**

* 入口文件

* @author zhuli

*

*/

@Controller

@RequestMapping(value="/test")

public class IndexController {

/**

* TestService

*/

@Autowired

private TestService TestService;

/**

* 留言板

*/

@Autowired

private GuestbookService guestbookService;

@RequestMapping(value="/test")

@ResponseBody

public String test() {

return Thread.currentThread().getName();

}

}

然后我们可以在浏览器中看到当前访问线程的名称:



但是有疑问啊,为什么每次刷新都是一样的名称呢?因为服务器请求处理速度很快,第一次请求很快就完毕,然后这个线程就空闲被释放,等你第二次再来请求的时候,还是这个线程的名称。

为了显示更加明显一点,我们做一个实验,修改一下代码:

[java] view
plain copy

print?

@RequestMapping(value="/test")

@ResponseBody

public String test() {

//运行慢一点

int i = 0;

int j = 0;

for (i = 0; i < 1000000000; i++) {

j++;

j = j + 1000;

j = j - 1000;

}

//然后再控制台输出每次请求的线程名称

System.out.print(Thread.currentThread().getName() + "\r\n");

return Thread.currentThread().getName();

}

然后继续在浏览器中访问:http://127.0.0.1:8090/test/test/,但是这次要连续按F5键刷新。这个时候我们看到控制台输出了四个不同的线程名称。也就是说,如果我们一个线程在忙碌中,那么会自动新生成一个线程,而线程与线程之间是互相不干扰的。



WEB编程中的危险用法。

[java] view
plain copy

print?

package com.alios.www.test.web;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.servlet.ModelAndView;

import com.alios.www.test.domain.GuestbookDo;

import com.alios.www.test.service.GuestbookService;

import com.alios.www.test.service.TestService;

/**

* 入口文件

* @author zhuli

*

*/

@Controller

@RequestMapping(value="/test")

public class IndexController {

/**

* TestService

*/

@Autowired

private TestService TestService;

/**

* 留言板

*/

@Autowired

private GuestbookService guestbookService;

private int i = 0; //i是一个全局变量,会常驻内存,线程可以共享这个变量。

@RequestMapping(value="/test")

@ResponseBody

public String test() {

//运行慢一点

int i = 0;

int j = 0;

for (i = 0; i < 1000000000; i++) {

j++;

j = j + 1000;

j = j - 1000;

}

//然后再控制台输出每次请求的线程名称

this.i++;

System.out.print(Thread.currentThread().getName() + ":" + this.i + "\r\n");

return Thread.currentThread().getName();

}

}

结果:



因为Spring的Controller类以及Dao,Service类是单例的模式,实例化之后会常驻内存,i是全局变量,也会常驻内存中,每次HTTP请求完毕之后,全局变量不会销毁。
只有在test()函数内的局部变量才会每次请求完毕就会销毁。
web开发是多线程的环境,如果随意定义全局变量,可能会导致数据之间的覆盖。

Spring框架如何解决多线程安全问题

用Spring框架开发web项目,我们的dao和Service,Controller一般都是单例的,并且是无状态的,那么这些只要常驻内存就可以了。但是对于那些HTTP请求进来的Request数据是如何处理的呢,这种“状态性”对象如果单例去解决的话,那就不和上面i的变量一样,每个请求就来就会改变这个i的值,不同的请求进来就会互相造成数据的覆盖。那Spring如何处理这些Request请求的数据只在当前的线程中有效呢?

回想一下上面我们用到的Thread对象,那么我们估计就有想法了。为什么我们能在我们的web程序中直接调用,我们先看一段创建线程的代码:

[java] view
plain copy

print?

package mythread;

public class Thread1 extends Thread

{

public void run()

{

System.out.println(this.getName());

}

public static void main(String[] args)

{

System.out.println(Thread.currentThread().getName());

Thread1 thread1 = new Thread1();

Thread1 thread2 = new Thread1 ();

thread1.start();

thread2.start();

}

}

结果:

main

Thread-0

Thread-1

从中我们可以很清晰的看到,Java能够通过Thread类来创建子线程,那么我们通过Spring框架入口进来的程序也可能是在Main函数中,通过创建子线程的方式来处理并行的请求。所以我们在我们并非请求的时候得到的线程名称是不一样的。

既然我们可以获取我们每个程序运行的时候所在的线程环境以及线程名称等详细信息,那么我们在全局作用域中可以开辟一块内存用于管理每个线程对应的内部运行数据,这样就可以实现每个线程可以独自运行并且互相没有干扰。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: