《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(); // 这里将出发线程InterruptedException System.out.println("main thread end."); } @Override public void run() { System.out.println("sub thread start."); try { Thread.sleep(99999999); } catch (InterruptedException e) { // 截获InterruptedException System.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:“守护线程(Daemon thread)”与“用户线程”。当虚拟机中将在用户线程结束后退出,如果没有用户线程,守护线程将随虚拟机一同退出。通过调用线程的setDaemon(true)方法设置线程为守护线程。
下面的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; @Override protected 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)会发生值被覆盖的情况。
解决
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; } }