读书人

Java多线程并发学习札记

发布时间: 2012-10-29 10:03:53 作者: rapoo

Java多线程并发学习笔记

《Java Concurrency in Practice》学习笔记:

?

Q:Thread.sleep()方法什么时候触发InterruptedException?

A:线程执行start()方法启动后,当执行sleep()方法的时候,线程又执行了interrupt()方法,会触发InterruptedException()

?

?

public class MultiThreadTest extends Thread {public static void main(String[] args) throws InterruptedException {System.out.println("main thread start.");Thread t = new MultiThreadTest();t.start();t.join(2000);t.interrupt(); // 这里将出发线程InterruptedExceptionSystem.out.println("main thread end.");}@Overridepublic void run() {System.out.println("sub thread start.");try {Thread.sleep(99999999);} catch (InterruptedException e) {// 截获InterruptedExceptionSystem.err.println("sub thread 被中断了");return;}System.out.println("sub thread end.");}}
?

?

// 输出结果main thread start.sub thread start.sub thread 被中断了main thread end.

Q:什么是守护线程?

A:Java有两种Thread:“守护线程—aemon thread)”与“用户线程”。当虚拟机中将在用户线程结束后退出,如果没有用户线程,守护线程将随虚拟机一同退出。通过调用线程的setDaemon(true)方法设置线程为守护线程。

?servlet原来是线程不安全的

?

下面的servlet用于计算两个输入值的乘机,打开两个浏览器,分别快速输入地址:

?

http://localhost:8888/xxxx/a=2&b=3

http://localhost:8888/xxxx/a=1&b=55

?

结果会发现两个浏览器输出的值是一样的,都是首先打开网址的结果。

?

?

public class TestServlet extends HttpServlet{private static final long serialVersionUID = 1L;int result;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Integer a = Integer.parseInt(req.getParameter("a"));Integer b = Integer.parseInt(req.getParameter("b"));if(a!=null && b != null){result = a * b;}try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}resp.getWriter().print(result);}}

?

问题:servlet容器复用了servelt实例,当多个线程同时访问这个实例的时候,如果servelt包含实例变量(int result)会发生值被覆盖的情况。

?

解决

?

    干掉实例变量(本例为result),让servlet变成无状态使用synchronized关键字,同步方法或者代码块,这样就只有一个线程可以访问同步代码块的内容

?

synchronized (this) {if (a != null && b != null) {result = a * b;}try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}resp.getWriter().print(result);}

?

方法和代码块同步

?

关键字synchronized放在非static方法,则进入该方法需要对象锁;同理进入synchronized (obj){...}的代码块,也需要obj的对象锁

?

举例说明:有一个BankAccount对象,两个线程访问它,一个是存款线程(deposit),一个存款线程(withdraw)

?

?

public class BankAccount {        // ......private int balance;public void deposit(int amount) {balance = balance + amount;}public void withdraw(int amount) {balance = balance - amount;}}
?

假设初始余额为1000,存款和取款线程各执行10万次,发现结果不确定,可能是几万,或者负数。

?

原因:多线程并发修改一个对象的实例属性时,值会相互影响(覆盖)。

?

解决:使用synchronized 同步临界代码块(critical section)或者同步方法:

?

?

public void deposit(int amount) {synchronized (this) {balance = balance + amount;}}public void withdraw(int amount) {synchronized (this) {balance = balance - amount;}}
?

?

《Java Concurrency in Practice》 ?写道Stateless objects are always thread-safe.
无状态的对象总是线程安全的.

?

?

?写道Thread-safe classes encapsulate any needed synchronization so that clients need not provide their own.
线程安全的类封装了所有需要同步的代码,所以客户端不需要再进行同步代码?

?

?

读书人网 >编程

热点推荐