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:“守护线程(Daemon 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)会发生值被覆盖的情况。
?
解决
?
?
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.?
?