我想的有点杂,先写在说。
1,关于线程安全,如果一个方法里面全部是局部变量,那么是没有必要同步的,也就是说它是线程安全的。也就是不必加synchronized,servelet里面的的HttpServlet就是这样, PrintWriter out = response.getWriter();这句话中这个out流本来可以作为HttpServlet的类变量的,但是如果是那样就需要同步了,影响效率呀。
2,关于锁,
class Test{ public synchronized void f1(){ //do something here } public void f2(){ synchronized(this){ //do something here } } }
上面的f1()和f2()效果一致, synchronized取得的锁都是Test某个实列(this)的锁.
比如: Test t = new Test();
线程A调用t.f2()时, 线程B无法进入t.f1(),直到t.f2()结束.
作用: 多线程中访问Test的同一个实例的同步方法时会进行同步.
也就是说在f1()前面加上synchronized ,那线程在调用这个方法的时候取得了这个对象的锁,也就是t的锁,
其他的线程想访问t的其他同步方法,比如f2()就不行,其实这样是不好的,很多时候我们用另外实例变量来锁。
class Test{ private static final Object obj=new Object(); public synchronized void f1(){ //do something here } public void f2(){ synchronized(obj){ //do something here } } }
此时,如果一个线程访问f2,它拿到的是obj对象的锁,别的线程依然可以访问f1().
3,原子性,先看代码:
package com.test; public class Test extends Thread { private int a = 0; private int b = 0; public static void main(String[] args) { Test test = new Test(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(test, "thread-" + i); thread.start(); } } public synchronized void doWrite() { a++; try { sleep((int)(Math.random()*100)); } catch (Exception e) { } b++; try { sleep((int)(Math.random()*100)); } catch (Exception e) { } } public synchronized void print() { System.out.println("" + Thread.currentThread().getName() + ":a:" + a); System.out.println("" + Thread.currentThread().getName() + ":b:" + b); } public void run() { f(); } public synchronized void f() { for (int i = 0; i < 5; i++) { doWrite(); print(); } } }
输出结果:
thread-0:a:1 thread-0:b:1 thread-0:a:2 thread-0:b:2 thread-0:a:3 thread-0:b:3 thread-0:a:4 thread-0:b:4 thread-0:a:5 thread-0:b:5 thread-1:a:6 thread-1:b:6 thread-1:a:7 thread-1:b:7 thread-1:a:8 thread-1:b:8 thread-1:a:9 thread-1:b:9 thread-1:a:10 thread-1:b:10 thread-2:a:11 thread-2:b:11 thread-2:a:12 thread-2:b:12 thread-2:a:13 thread-2:b:13 thread-2:a:14 thread-2:b:14 thread-2:a:15 thread-2:b:15 thread-3:a:16 thread-3:b:16 thread-3:a:17 thread-3:b:17 thread-3:a:18 thread-3:b:18 thread-3:a:19 thread-3:b:19 thread-3:a:20 thread-3:b:20 thread-4:a:21 thread-4:b:21 thread-4:a:22 thread-4:b:22 thread-4:a:23 thread-4:b:23 thread-4:a:24 thread-4:b:24 thread-4:a:25 thread-4:b:25 thread-5:a:26 thread-5:b:26 thread-5:a:27 thread-5:b:27 thread-5:a:28 thread-5:b:28 thread-5:a:29 thread-5:b:29 thread-5:a:30 thread-5:b:30 thread-6:a:31 thread-6:b:31 thread-6:a:32 thread-6:b:32 thread-6:a:33 thread-6:b:33 thread-6:a:34 thread-6:b:34 thread-6:a:35 thread-6:b:35 thread-7:a:36 thread-7:b:36 thread-7:a:37 thread-7:b:37 thread-7:a:38 thread-7:b:38 thread-7:a:39 thread-7:b:39 thread-7:a:40 thread-7:b:40 thread-8:a:41 thread-8:b:41 thread-8:a:42 thread-8:b:42 thread-8:a:43 thread-8:b:43 thread-8:a:44 thread-8:b:44 thread-8:a:45 thread-8:b:45 thread-9:a:46 thread-9:b:46 thread-9:a:47 thread-9:b:47 thread-9:a:48 thread-9:b:48 thread-9:a:49 thread-9:b:49 thread-9:a:50 thread-9:b:50
我们可以看到是很标准的输出。
我们在run方法里面改点东西:
package com.test; public class Test extends Thread { private int a = 0; private int b = 0; public static void main(String[] args) { Test test = new Test(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(test, "thread-" + i); thread.start(); } } public synchronized void doWrite() { a++; try { sleep((int)(Math.random()*100)); } catch (Exception e) { } b++; try { sleep((int)(Math.random()*100)); } catch (Exception e) { } } public synchronized void print() { System.out.println("" + Thread.currentThread().getName() + ":a:" + a); System.out.println("" + Thread.currentThread().getName() + ":b:" + b); } public void run() { for (int i = 0; i < 5; i++) { doWrite(); print(); } } }
输出的结果就不确定了:
thread-0:a:10 thread-0:b:10 thread-1:a:10 thread-1:b:10 thread-2:a:10 thread-2:b:10 thread-3:a:10 thread-3:b:10 thread-4:a:10 thread-4:b:10 thread-5:a:10 thread-5:b:10 thread-6:a:10 thread-6:b:10 thread-7:a:10 thread-7:b:10 thread-8:a:10 thread-8:b:10 thread-9:a:10 thread-9:b:10 thread-0:a:20 thread-0:b:20 thread-1:a:20 thread-1:b:20 thread-2:a:20 thread-2:b:20 thread-3:a:20 thread-3:b:20 thread-4:a:20 thread-4:b:20 thread-5:a:20 thread-5:b:20 thread-6:a:20 thread-6:b:20 thread-7:a:20 thread-7:b:20 thread-8:a:20 thread-8:b:20 thread-9:a:20 thread-9:b:20 thread-0:a:30 thread-0:b:30 thread-1:a:30 thread-1:b:30 thread-2:a:30 thread-2:b:30 thread-3:a:30 thread-3:b:30 thread-4:a:30 thread-4:b:30 thread-5:a:30 thread-5:b:30 thread-6:a:30 thread-6:b:30 thread-7:a:30 thread-7:b:30 thread-8:a:30 thread-8:b:30 thread-9:a:30 thread-9:b:30 thread-0:a:40 thread-0:b:40 thread-1:a:40 thread-1:b:40 thread-2:a:40 thread-2:b:40 thread-3:a:40 thread-3:b:40 thread-4:a:40 thread-4:b:40 thread-5:a:40 thread-5:b:40 thread-6:a:40 thread-6:b:40 thread-7:a:40 thread-7:b:40 thread-8:a:40 thread-8:b:40 thread-9:a:40 thread-9:b:40 thread-0:a:50 thread-0:b:50 thread-1:a:50 thread-1:b:50 thread-2:a:50 thread-2:b:50 thread-3:a:50 thread-3:b:50 thread-4:a:50 thread-4:b:50 thread-5:a:50 thread-5:b:50 thread-6:a:50 thread-6:b:50 thread-7:a:50 thread-7:b:50 thread-8:a:50 thread-8:b:50 thread-9:a:50 thread-9:b:50
我们的目的就是要 完数据后在输出,所以应该确保这个过程的原子性。直接写在run方法里面就没能确保原子性。
先写到这,以后在加吧。