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(); // 这里将出发线程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原来是线程不安全的

 

下面的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)会发生值被覆盖的情况。

 

解决

 

  1. 干掉实例变量(本例为result),让servlet变成无状态
  2. 使用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.
线程安全的类封装了所有需要同步的代码,所以客户端不需要再进行同步代码
 

 

 

你可能感兴趣的:(java多线程)