• 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 }
    结果:
    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 }
    结果:
    ...
    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对象,并且独立于其他对象。
  • 相关阅读:
    线程和信号
    线程取消状态和取消类型
    线程本地缓存
    线程安全函数的概念
    线程/同步对象的属性对象
    查看安全策略
    ss性能
    三次握手四次断开
    线程同步--屏障
    vs2008 编译时候 自动关闭 问题解决方法
  • 原文地址:https://www.cnblogs.com/wasp520/p/2559425.html
Copyright © 2020-2023  润新知