JAVA多线程--2 锁
多线程访问资源时,如果没有做处理,很容易出现资源错乱,必须通过锁机制实现资源共享
例如:
View Code
1 package multithread;
2 import java.util.HashMap;
3 import java.util.Map;
4 import java.util.concurrent.ConcurrentHashMap;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.Executors;
7 public class NoLockDemo {
8 public static void main(String[] args) throws InterruptedException {
9 NoLockDemo ld=new NoLockDemo();
10 ExecutorService exec=Executors.newFixedThreadPool(5);
11 TestNumber t=ld.new TestNumber();
12 for(int i=0;i<50;i++){
13 exec.execute(t);
14 }
15 }
16 class TestNumber extends Thread{
17 int num=0;
18 Map<Integer, Integer> map=new HashMap<Integer, Integer>();
19 Map<Integer, Integer> correntmap=new ConcurrentHashMap<Integer, Integer>();
20 public TestNumber(){
21 }
22 public int addNum(){
23 num++;
24 num++;
25 //map.put(num, num);
26 correntmap.put(num, num);
27 return num;
28 }
29 public void run(){
30 setName("test-");
31 addNum();
32 System.out.println(num);
33 //System.out.println(map);
34 System.out.println(correntmap);
35 }
36 }
37 }
2 import java.util.HashMap;
3 import java.util.Map;
4 import java.util.concurrent.ConcurrentHashMap;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.Executors;
7 public class NoLockDemo {
8 public static void main(String[] args) throws InterruptedException {
9 NoLockDemo ld=new NoLockDemo();
10 ExecutorService exec=Executors.newFixedThreadPool(5);
11 TestNumber t=ld.new TestNumber();
12 for(int i=0;i<50;i++){
13 exec.execute(t);
14 }
15 }
16 class TestNumber extends Thread{
17 int num=0;
18 Map<Integer, Integer> map=new HashMap<Integer, Integer>();
19 Map<Integer, Integer> correntmap=new ConcurrentHashMap<Integer, Integer>();
20 public TestNumber(){
21 }
22 public int addNum(){
23 num++;
24 num++;
25 //map.put(num, num);
26 correntmap.put(num, num);
27 return num;
28 }
29 public void run(){
30 setName("test-");
31 addNum();
32 System.out.println(num);
33 //System.out.println(map);
34 System.out.println(correntmap);
35 }
36 }
37 }
结果:
6
6
6
8
10
{6=6, 8=8, 2=6, 10=10, 4=6}
{6=6, 8=8, 2=6, 10=10, 4=6} ...
其中。2=6, 10=10, 4=6 ,对于我们程序来说
correntmap.put(num, num);不应该有这样的结果,但是这样错乱的结果产生了,并且是多线程访问资源导致
而如果我们使用HashMap而不用ConcurrentHashMap,就会报错:Exception in thread "pool-1-thread-5" java.util.ConcurrentModificationException
因此在多线程操作中,尽量使用concurrent包下的类
如何解决此类问题?
通过关键字synchronized或者Lock实现资源竞争访问。
对于他们的总结如下:
* @author Administrator
* 1、synchronized可用于方法、对象、static方法
* synchronized method 锁对象就是本身对象,同synchroniezd(this){};
* synchronized(obj) 其中obj就是一个对象,只是实现了一个同步的代码块,使用byte obj=new byte[0]优化
* synchronized static method 锁对象类对象,同synchronized(Foo.class)
*
* 2、与Lock的区别
* synchronized:所有对象都自动含有单一锁,jvm负责跟踪锁次数,无需人工干预。锁的获取释放在同一模块,并且相反顺序
* Lock:基于栈中的框架而不是某个具体的对象,需要设置锁的开始和结束。可以提供无条件的、可轮询的、定时的、可中断的锁获取操作。
*
例如:
View Code
1 public class LockDemo {
2 public static void main(String[] args) throws InterruptedException {
3 LockDemo ld=new LockDemo();
4 ExecutorService exec=Executors.newFixedThreadPool(5);
5 TestNumber t=ld.new TestNumber();
6 for(int i=0;i<50;i++){
7 exec.execute(t);
8 }
9 //exec.shutdown();
10 final AttemptingLock alock=ld.new AttemptingLock();
11 alock.untimed();
12 alock.timed();
13 new Thread(){
14 {
15 setDaemon(true);
16 setName("test attemptinglock");
17 }
18 public void run(){
19 while(true){
20 alock.lock.lock();
21 }
22 }
23 }.start();
24 Thread.sleep(1000);
25 alock.untimed();
26 alock.timed();
27 exec.shutdown();
28 }
29 class AttemptingLock {
30 private ReentrantLock lock=new ReentrantLock();
31 public void untimed(){
32 boolean captured=lock.tryLock();
33 System.out.println("captured:"+captured);
34 if(captured){
35 lock.unlock();
36 }
37 }
38 public void timed(){
39 boolean captured = false;
40 try {
41 captured = lock.tryLock(2,TimeUnit.SECONDS);
42 System.out.println("timed captured:"+captured);
43 } catch (InterruptedException e) {
44 // TODO Auto-generated catch block
45 e.printStackTrace();
46 }finally{
47 if(captured){
48 lock.unlock();
49 }
50 }
51 }
52 }
53 class TestNumber extends Thread{
54 int num=0;
55 Map<Integer, Integer> map=new HashMap<Integer, Integer>();
56 Map<Integer, Integer> correntmap=new ConcurrentHashMap<Integer, Integer>();
57 private Lock lock=new ReentrantLock();
58 //byte 优于Object Object obj=new Object();
59 private byte[] obj=new byte[0];
60 public TestNumber(){
61 }
62 public synchronized int addNum(){
63 num++;
64 num++;
65 //map.put(num, num);
66 correntmap.put(num, num);
67 return num;
68 }
69 public int addNumSyschronizedObject(){
70 synchronized (obj) {
71 num++;
72 num++;
73 correntmap.put(num, num);
74 return num;
75 }
76 /* 同方法同步
77 synchronized(this){
78 num++;
79 num++;
80 correntmap.put(num, num);
81 return num;
82 }
83 */
84 }
85 public int lockAddNum(){
86 lock.lock();
87 try{
88 num++;
89 num++;
90 //map.put(num, num);
91 correntmap.put(num, num);
92 }finally{
93 lock.unlock();
94 }
95 return num;
96 }
97 public void run(){
98 setName("test-");
99 //addNum();
100 lockAddNum();
101 System.out.println(num);
102 //System.out.println(map);
103 System.out.println(correntmap);
104 }
105 }
106 static class Test2{
107 private static int num=0;
108 public synchronized static int getNum(){
109 return num++;
110 }
111 }
112 }
2 public static void main(String[] args) throws InterruptedException {
3 LockDemo ld=new LockDemo();
4 ExecutorService exec=Executors.newFixedThreadPool(5);
5 TestNumber t=ld.new TestNumber();
6 for(int i=0;i<50;i++){
7 exec.execute(t);
8 }
9 //exec.shutdown();
10 final AttemptingLock alock=ld.new AttemptingLock();
11 alock.untimed();
12 alock.timed();
13 new Thread(){
14 {
15 setDaemon(true);
16 setName("test attemptinglock");
17 }
18 public void run(){
19 while(true){
20 alock.lock.lock();
21 }
22 }
23 }.start();
24 Thread.sleep(1000);
25 alock.untimed();
26 alock.timed();
27 exec.shutdown();
28 }
29 class AttemptingLock {
30 private ReentrantLock lock=new ReentrantLock();
31 public void untimed(){
32 boolean captured=lock.tryLock();
33 System.out.println("captured:"+captured);
34 if(captured){
35 lock.unlock();
36 }
37 }
38 public void timed(){
39 boolean captured = false;
40 try {
41 captured = lock.tryLock(2,TimeUnit.SECONDS);
42 System.out.println("timed captured:"+captured);
43 } catch (InterruptedException e) {
44 // TODO Auto-generated catch block
45 e.printStackTrace();
46 }finally{
47 if(captured){
48 lock.unlock();
49 }
50 }
51 }
52 }
53 class TestNumber extends Thread{
54 int num=0;
55 Map<Integer, Integer> map=new HashMap<Integer, Integer>();
56 Map<Integer, Integer> correntmap=new ConcurrentHashMap<Integer, Integer>();
57 private Lock lock=new ReentrantLock();
58 //byte 优于Object Object obj=new Object();
59 private byte[] obj=new byte[0];
60 public TestNumber(){
61 }
62 public synchronized int addNum(){
63 num++;
64 num++;
65 //map.put(num, num);
66 correntmap.put(num, num);
67 return num;
68 }
69 public int addNumSyschronizedObject(){
70 synchronized (obj) {
71 num++;
72 num++;
73 correntmap.put(num, num);
74 return num;
75 }
76 /* 同方法同步
77 synchronized(this){
78 num++;
79 num++;
80 correntmap.put(num, num);
81 return num;
82 }
83 */
84 }
85 public int lockAddNum(){
86 lock.lock();
87 try{
88 num++;
89 num++;
90 //map.put(num, num);
91 correntmap.put(num, num);
92 }finally{
93 lock.unlock();
94 }
95 return num;
96 }
97 public void run(){
98 setName("test-");
99 //addNum();
100 lockAddNum();
101 System.out.println(num);
102 //System.out.println(map);
103 System.out.println(correntmap);
104 }
105 }
106 static class Test2{
107 private static int num=0;
108 public synchronized static int getNum(){
109 return num++;
110 }
111 }
112 }
结果:
...
captured:true
timed captured:true
88
{40=40, 22=22, 12=12, 96=96, 20=20, 6=6, 68=68, 62=62, 48=48, 34=34, 28=28, 42=42, 18=18, 88=88, 74=74, 56=56, 84=84, 98=98, 46=46, 70=70, 90=90, 36=36, 26=26, 8=8, 82=82, 72=72, 100=100, 54=54, 2=2, 86=86, 44=44, 58=58, 78=78, 92=92, 64=64, 16=16, 30=30, 10=10, 52=52, 38=38, 80=80, 24=24, 60=60, 14=14, 94=94, 66=66, 32=32, 4=4, 76=76, 50=50}
{40=40, 22=22, 12=12, 96=96, 20=20, 6=6, 68=68, 62=62, 48=48, 34=34, 28=28, 42=42, 18=18, 88=88, 74=74, 56=56, 84=84, 98=98, 46=46, 70=70, 90=90, 36=36, 26=26, 8=8, 82=82, 72=72, 100=100, 54=54, 2=2, 86=86, 44=44, 58=58, 78=78, 92=92, 64=64, 16=16, 30=30, 10=10, 52=52, 38=38, 80=80, 24=24, 60=60, 14=14, 94=94, 66=66, 32=32, 4=4, 76=76, 50=50}
captured:false
timed captured:false ...
此时不会出现刚才那种错乱
Lock可以通过tryLock方法判断是否可以获取锁,当不能获取时可以进行处理,同时tryLock方法可以设置超时时间。
对于Lock必须显式的调用lock()方法与unlock()方法进行释放。使用Lock更加灵活。
总结:
1、通常Lock会比synchronized高效
2、使用synchronized--只互斥那些你绝对必须互斥的部分
3、synchronized的代码可读性比较高
4、Atomic对象只能处理比较简单的情况,包括你只有一个要被修改的Atomic对象,并且独立于其他对象。