多线程与集合类

synchronized关键字加锁的原理,其实是对对象加锁,不论你是在方法前加synchronized还是语句块前加,锁住的都是对象整体,但是ConcurrentHashMap的同步机制和这个不同,它不是加synchronized关键字,而是基于lock操作的,这样的目的是保证同步的时候,锁住的不是整个对象。ConcurrentHashMap是基于一个叫Segment数组的.

 

1、HashMap和HashTable

      相同点:二者都实现了Map接口,因此具有一系列Map接口提供的方法。

      不同点:

           1、HashMap继承了AbstractMap,而HashTable继承了Dictionary。

            2、HashMap非线程安全,HashTable线程安全,到处都是synchronized关键字。

           3、因为HashMap没有同步,所以处理起来效率较高。

           4、HashMap键、值都允许为null,HashTable键、值都不允许有null。

           5、HashTable使用Enumeration,HashMap使用Iterator。

      这些就是一些比较突出的不同点,实际上他们在实现的过程中会有很多的不同,如初始化的大小、计算hash值的方式等等。毕竟这两个类包含了很多方法,有很重要的功能,所以其他不同点,请感兴趣的读者自己去看源码,去研究。笔者推荐使用HashMap,因为她提供了比HashTable更多的方法,以及较高的效率,如果大家需要在多线程环境中使用,那么用Collections类来做一下同步即可。

2Set接口和List接口

  相同点:都实现了Collection接口

    不同点:

          1、Set接口不保证维护元素的顺序,而且元素不能重复。List接口维护元素的顺序,而且元素可以重复。

      2、关于Set元素如何保证元素不重复,我将在下面的博文中给出。

3、ArrayList和LinkList

    相同点:都实现了Collection接口

      不同点:ArrayList基于数组,具有较高的查询速度,而LinkedList基于双向循环列表,具有较快的添加或者删除的速度,二者的区别,其实就是数组和列表的区别。上文有详细的分析。

4SortedSetSortedMap

      二者都提供了排序的功能。 来看一个小例子:

[java] view plain copy

1. public static void main(String[] args) {  

2.           

3.         SortedMap<String, Integer> map = new TreeMap<String, Integer>();  

4.         map.put("zgg"1);  

5.         map.put("erqing"3);  

6.         map.put("niu"0);  

7.         map.put("abc"2);  

8.         map.put("aaa"5);  

9.           

10.        Set<String> keySet = map.keySet();  

11.        for (String string : keySet) {  

12.            System.out.print(map.get(string)+" ");  

13.        }  

14.    }  

输出:5 2 3 0 1

从结果看得出:SortedMap具有自动排序功能

5TreeMapHashMap

    HashMap具有较高的速度(查询)TreeMap则提供了按照键进行排序的功能。

6HashSetLinkedHashSet

    HashSet,为快速查找而设计的Set。存入HashSet的对象必须实现hashCode()equals()

    LinkedHashSet,具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序),于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。

7TreeSetHashSet

    TreeSet: 提供排序功能的Set,底层为树结构 。相比较HashSet其查询速度低,如果只是进行元素的查询,我们一般使用HashSet

8、ArrayList和Vector

      同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的。

      数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半

9、Collection和Collections

      Collection是一系列单值集合类的父接口,提供了基本的一些方法,而Collections则是一系列算法的集合。里面的属性和方法基本都是static的,也就是说我们不需要实例化,直接可以使用类名来调用。

 

 

Java IO主要主要在java.io包下,分为四大块近80个类:

1、基于字节操作的I/O接口:InputStream和OutputStream

2、基于字符操作的I/O接口:Writer和Reader

3、基于磁盘操作的I/O接口:File

4、基于网络操作的I/O接口:Socket(不在java.io包下)

 

 

 

 

 

 

1. 定义一个接口,该接口里有需要实现的方法,并且编写实际的实现类。

2. 定义一个InvocationHandler类,实现InvocationHandler接口,重写invoke()方法,且添加getProxy()方法。

总结一下动态代理实现过程:

1. 通过getProxyClass0()生成代理类。

2. 通过Proxy.newProxyInstance()生成代理类的实例对象,创建对象时传入InvocationHandler类型的实例。

3. 调用新实例的方法,即此例中的add(),即原InvocationHandler类中的invoke()方法。

UserService.java, 只有一个方法add()。

[java] view plain copy

1. package com.adam.java.basic;  

2.   

3. public interface UserService {  

4.     public abstract void add();  

5. }  


建一个该接口的实现类UserServiceImpl.java

[java] view plain copy

1. package com.adam.java.basic;  

2. public class UserServiceImpl implements UserService {  

3.   

4.     @Override  

5.     public void add() {  

6.         System.out.println("----- add -----");  

7.     }  

8. }  


建一个代理处理类MyInvocationHandler.java

[java] view plain copy

1. package com.adam.java.basic;  

2. import java.lang.reflect.InvocationHandler;  

3. import java.lang.reflect.Method;  

4. import java.lang.reflect.Proxy;  

5.   

6. public class MyInvocationHandler implements InvocationHandler {  

7.   

8.     private Object target;  

9.   

10.    public MyInvocationHandler(Object target) {  

11.        super();  

12.        this.target = target;  

13.    }  

14.  

15.    public Object getProxy() {  

16.        return Proxy.newProxyInstance(Thread.currentThread()  

17.                .getContextClassLoader(), target.getClass().getInterfaces(),  

18.                this);  

19.    }  

20.  

21.    @Override  

22.    public Object invoke(Object proxy, Method method, Object[] args)  

23.            throws Throwable {  

24.        System.out.println("----- before -----");  

25.        Object result = method.invoke(target, args);  

26.        System.out.println("----- after -----");  

27.        return result;  

28.    }  

29.}  


测试类

1. package com.adam.java.basic;  

2. public class DynamicProxyTest {  

3.   

4.     public static void main(String[] args) {  

5.         UserService userService = new UserServiceImpl();  

6.         MyInvocationHandler invocationHandler = new MyInvocationHandler(  

7.                 userService);  

8.   

9.         UserService proxy = (UserService) invocationHandler.getProxy();  

10.        proxy.add();  

11.    }  

12.}  

JDK本身有实现动态代理技术,但是略有限制,即被代理的类必须实现某个接口,否则无法使用JDK自带的动态代理,因此,如果不满足条件,就只能使用另一种更加灵活,功能更加强大的动态代理技术—— CGLIB.

 

 JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理 
示例 

   业务类:

[java] viewplain copy

1.  package net.battier.dao;  

2.    

3.  public interface BookFacade {  

4.      public void addBook();  

5.  }  

   

[java] viewplain copy

1.  package net.battier.dao.impl;  

2.    

3.  /** 

4.   * 这个是没有实现接口的实现类 

5.   *  

6.   * @author student 

7.   *  

8.   */  

9.  public class BookFacadeImpl1 {  

10.     public void addBook() {  

11.         System.out.println("增加图书的普通方法...");  

12.     }  

13. }  

  代理:

   

[java] viewplain copy

1.  package net.battier.proxy;  

2.    

3.  import java.lang.reflect.Method;  

4.    

5.  import net.sf.cglib.proxy.Enhancer;  

6.  import net.sf.cglib.proxy.MethodInterceptor;  

7.  import net.sf.cglib.proxy.MethodProxy;  

8.    

9.  /** 

10.  * 使用cglib动态代理 

11.  *  

12.  * @author student 

13.  *  

14.  */  

15. public class BookFacadeCglib implements MethodInterceptor {  

16.     private Object target;  

17.   

18.     /** 

19.      * 创建代理对象 

20.      *  

21.      * @param target 

22.      * @return 

23.      */  

24.     public Object getInstance(Object target) {  

25.         this.target = target;  

26.         Enhancer enhancer = new Enhancer();  

27.         enhancer.setSuperclass(this.target.getClass());  

28.         // 回调方法  

29.         enhancer.setCallback(this);  

30.         // 创建代理对象  

31.         return enhancer.create();  

32.     }  

33.   

34.     @Override  

35.     // 回调方法  

36.     public Object intercept(Object obj, Method method, Object[] args,  

37.             MethodProxy proxy) throws Throwable {  

38.         System.out.println("事物开始");  

39.         proxy.invokeSuper(obj, args);  

40.         System.out.println("事物结束");  

41.         return null;  

42.   

43.   

44.     }  

45.   

46. }  

  测试;

   

[java] viewplain copy

1.  package net.battier.test;  

2.    

3.  import net.battier.dao.impl.BookFacadeImpl1;  

4.  import net.battier.proxy.BookFacadeCglib;  

5.    

6.  public class TestCglib {  

7.        

8.      public static void main(String[] args) {  

9.          BookFacadeCglib cglib=new BookFacadeCglib();  

10.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  

11.         bookCglib.addBook();  

12.     }  

13. }  

简述synchronized和java.util.concurrent.locks.Lock的异同 ?

主要相同点:Lock能完成synchronized所实现的所有功能

主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。

 

线程安全问题,一般情况下,如果一个对象的状态是可变的,同时它又是共享的(即至少可被多于一个线程同时访问),则它存在线程安全问题。

 

原子性意味着一个线程一次只能执行由一个指定监控对象(lock)保护的代码,从而防止多个线程在更新共享状态时相互冲突。可见性则更为微妙;它要对付内存缓存和编译器优化的各种反常行为。一般来说,线程以某种不必让其他线程立即可以看到的方式(不管这些线程在寄存器中、在处理器特定的缓存中,还是通过指令重排或者其他编译器优化),不受缓存变量值的约束。

 

原子变量类基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入。

 

synchronized关键字是基于阻塞的锁机制,也就是说当一个线程拥有锁的时候,访问同一资源的其它线程需要等待,直到该线程释放锁,这里会有些问题:首先,如果被阻塞的线程优先级很高很重要怎么办?其次,如果获得锁的线程一直不释放锁怎么办?(这种情况是非常糟糕的)。还有一种情况,如果有大量的线程来竞争资源,那CPU将会花费大量的时间和资源来处理这些竞争(事实上CPU的主要工作并非这些),同时,还有可能出现一些例如死锁之类的情况。

 

Compare and swap(CAS)

每一个CAS操作过程都包含三个运算符:一个内存地址V,一个期望的值A和一个新值B,操作的时候如果这个地址上存放的值等于这个期望的值A,则将地址上的值赋为新值B,否则不做任何操作。CAS的基本思路就是,如果这个地址上的值和期望的值相等,则给其赋予新值,否则不做任何事儿,但是要返回原值是多少。

 

CAS (compare and swap) + volatile和native方法

 

数据结构包括两大类:线性结构和非线性结构,线性结构包括:数组、链表、队列、栈等,非线性结构包括树、图、表等及衍生类结构。

 

 

Collections位集合类提供线程安全的支持

对于有些非线程安全的集合类,如HashMap,我们可以通过Collections的一些方法,使得HashMap变为线程安全的类,如:Collections.synchronizedMap(newHashMap());

 

 

excutor框架

Java中excutor只是一个接口,但它为一个强大的同步框架做好了基础,其实现可以用于异步任务执行,支持很多不同类型的任务执行策略。excutor框架适用于生产者-消费者模式,是一个非常成熟的框架

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值