一 Atmoic类synchronized加锁和look枷锁机制对比

控制线程同步的有Atmoic类和 synchronized加锁和look枷锁机制。但是一般情况下还是去优先选用 synchronized,主要原因有:
1.现在synchronized也被优化,性能也有提高
2.look加锁显然比synchronized控制的范围根据准确,性能高,但是代码却不易阅读。所以只有在及其需要性能时可以考虑使用
3.Atmoic对象只有在非常简单的情况下才有用,所以只有在性能方法的需求能够明确指示时才去考虑。

二、免锁容器:

  1. 容器也会应用于并非编程当中,**使得可以被并发的读取和写入**。早期的VectorHashTable这类早期容器中具有许多的synchronized方法,当他们应用在非多线程中时,会导致不可接受的开销。所以javase5中特别添加了新的容器,通过使用更加灵活的技巧消除了锁,提高线程安全的性能。

1.免锁容器背后的策略:

对容器的修改与读取同时发生时,修改时会先复制容器数据,并在一个单独的副本上去执行修改操作,同时这个过程时不可见的,只有但修改完成时候,才会与源数据交换,而且这个交换的操作是原子性的。之后读取者就可以看到这个修改过的操作了。所以,容器在没用修改完成时去读取,这时读取者只能读取到没用修改的数据(源数据)
2.免锁容器:
CopyOnWriteArrayList:
允许多个迭代器同时去遍历修改,也允许列表被遍历时调用remove()不会去包ConcurrentModificationException异常

  1. public class CopyArrayListDemo {
  2. public static void main(String[] args) {
  3. CopyOnWriteArrayList<String> copy = new CopyOnWriteArrayList<>();
  4. copy.addAll(Arrays.asList("001", "002", "003"));
  5. new Thread() {
  6. @Override
  7. public void run() {
  8. System.out.println("被线程" + Thread.currentThread().getName() + "修改之前的集合" + copy);
  9. for (int i = 0; i < copy.size(); i++) {
  10. try {
  11. copy.set(i, "0" + i);
  12. TimeUnit.SECONDS.sleep(1);
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. }
  18. }.start();
  19. new Thread() {
  20. @Override
  21. public void run() {
  22. System.out.println("修改后的集合:");
  23. for (String s : copy) {
  24. System.out.println(s);
  25. copy.remove(s);
  26. }
  27. System.out.println("remove:后的集合"+copy);
  28. }
  29. }.start();
  30. }
  31. }
  1. 其余CopyOnWriteArraySetconcurentHashMapconcurentLinkedQueue都使用了同样的技术。允许并非的读取和写入。同样在任何修改完成之前,读取者看不到他。只能看到源数据。

三、乐观锁:

  1. 尽管Atomic对象将执行像derementAndGet()这样的原子性操作,某些Atomic还允许你执行所谓的“乐观加锁”。即在执行某项计算时,实际上没用使用互斥,当准备更新这个对象时,需要使用一个compareAndSet()方法来将旧值和新值一起提交。如果旧值与它在对象中的旧址不同时,那么这个操作更新操作将失败。这个时候,我们必须在失败后去执行一些任务。

示列:乐观锁局基本原理

  1. public class AtomicDemo {
  2. public static void main(String[] args) {
  3. AtomicInteger integer = new AtomicInteger();
  4. integer.addAndGet(10);
  5. new Thread(() -> {
  6. int oldValue = integer.get();
  7. try {
  8. TimeUnit.MILLISECONDS.sleep(200);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. int newValue = oldValue + 3;
  13. System.out.println("老的值为" + oldValue + "要更新的值为 " + newValue);
  14. if (!integer.compareAndSet(oldValue, newValue)) {
  15. System.out.println(Thread.currentThread().getName() + "更新失败");
  16. }
  17. }).start();
  18. new Thread(() -> {
  19. int oldValue = integer.get();
  20. int newValue = oldValue + 3;
  21. if (!integer.compareAndSet(oldValue, newValue)) {
  22. System.out.println("更新失败");
  23. } else {
  24. System.out.println(Thread.currentThread().getName() + "更新成功");
  25. }
  26. }).start();
  27. }
  28. }
  1. 上述程序便是乐观锁的原理:线程一要去跟新一个数据,但是遇到了延迟,这个时候线程二抢先跟新了。此时当延迟过后,线程一integer.compareAndSet(oldValue, newValue)的时候没发现,老的值和Aomtic对象中的值不同了,此时便跟新失败。这个时候我们是乐观的,我们希望数据没用任何任务插入修改。但又保持了数据的未锁状态。

四、ReadWriterLock:

  1. ReadWriterLock对于向数据结构相对不频繁的写入,但是有多个任务要去经常的去读取这个数据时。如果写锁被其他任务持有,那么任何读锁不能访问,直到这个写锁被释放为止。当锁写被读锁获得时候,那么写锁同样等到读锁被释放之后才能进行。
  1. class ReadDmo implements Runnable{
  2. ReentrantReadWriteLock reent;
  3. List list;
  4. ReadDmo(List list,ReentrantReadWriteLock reent){
  5. this.list=list;
  6. this.reent=reent;
  7. }
  8. @Override
  9. public void run() {
  10. Lock lock = reent.readLock();
  11. lock.lock();
  12. try {
  13. for (int i = 0; i < list.size(); i++) {
  14. System.out.println(Thread.currentThread().getName()+":"+list.get(i));
  15. }
  16. }finally {
  17. lock.unlock();
  18. }
  19. }
  20. }
  21. public class Demo {
  22. public static void main(String[] args) {
  23. ReentrantReadWriteLock reent = new ReentrantReadWriteLock();
  24. final List<Integer> list = new ArrayList<>();
  25. new Thread() {
  26. @Override
  27. public void run() {
  28. Lock lock = reent.writeLock();
  29. lock.lock();
  30. try {
  31. for (int i = 0; i < 20; i++) {
  32. list.add(i);
  33. }
  34. } finally {
  35. lock.unlock();//如果不释放锁,读取的任务将被阻塞
  36. }
  37. }
  38. }.start();
  39. ExecutorService service = Executors.newCachedThreadPool();
  40. for (int i = 0; i <4 ; i++) {
  41. service.execute(new ReadDmo(list,reent));
  42. }
  43. }
  44. }
  1. **同样当锁先被读取锁获得时,如果不释放那么写锁也将进入等待知道读取锁释放**
  1. public class ReadDemo {
  2. static volatile boolean falg = false;
  3. private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
  4. public static void main(String[] args) throws InterruptedException {
  5. new Thread(() -> {
  6. Lock lock = ReadDemo.lock.readLock();
  7. try {
  8. System.out.println("进入读锁");
  9. lock.lock();
  10. TimeUnit.SECONDS.sleep(100);
  11. System.out.println("写锁释放");
  12. lock.unlock();
  13. } catch (Exception e) {
  14. System.out.println("");
  15. }
  16. }).start();
  17. TimeUnit.MILLISECONDS.sleep(10);
  18. new Thread(() -> {
  19. try {
  20. Lock lock = ReadDemo.lock.writeLock();
  21. System.out.println("进入读取线程,但会被阻塞");
  22. try {
  23. lock.lock();
  24. System.out.println("进入写锁");
  25. lock.unlock();
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. } finally {
  30. }
  31. }).start();
  32. }
  33. }

示列: ReadWriterLock配合Boolean类型控制先写入在读取

  1. public class ReaderWriterFile {
  2. private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
  3. volatile boolean falg=false;
  4. private class WriterTask implements Runnable{
  5. private String fileName;
  6. private String content;
  7. WriterTask(String fileName,String content){
  8. this.fileName = fileName;
  9. this.content=content;
  10. }
  11. @Override
  12. public void run() {
  13. System.out.println("11111");
  14. Lock wlock = lock.writeLock();
  15. wlock.lock();
  16. try {
  17. BufferedWriter writer = new BufferedWriter(
  18. new FileWriter(new File(fileName), true));
  19. writer.write(content);
  20. TimeUnit.SECONDS.sleep(1);
  21. writer.flush();
  22. writer.close();
  23. falg=true;
  24. }catch (Exception e){
  25. } finally {
  26. wlock.unlock();
  27. }
  28. }
  29. }
  30. private class ReaderTask implements Runnable{
  31. private String fileName;
  32. ReaderTask(String fileName){
  33. this.fileName = fileName;
  34. }
  35. @Override
  36. public void run() {
  37. System.out.println("=====");
  38. while (!Thread.interrupted()) {
  39. Lock rlock = lock.readLock();
  40. rlock.lock();
  41. try {
  42. BufferedReader reader = new BufferedReader(new FileReader(new File(fileName)));
  43. String temp;
  44. while ((temp = reader.readLine()) != null) {
  45. System.out.println(temp);
  46. }
  47. } catch (Exception e) {
  48. } finally {
  49. rlock.unlock();
  50. }
  51. }
  52. }
  53. }
  54. public static void main(String[] args) throws InterruptedException {
  55. final ReaderWriterFile readerWriterFile = new ReaderWriterFile();
  56. WriterTask writerTask = readerWriterFile.new WriterTask("a", "higklmn" + " 111111" + "22");
  57. final ReaderTask readerTask = readerWriterFile.new ReaderTask("a");
  58. new Thread(readerTask).start();
  59. new Thread(readerTask).start();
  60. new Thread(readerTask).start();
  61. new Thread(writerTask).start();
  62. }
  63. }
  1. 程序中的两个读取线程同时进行,但是值有当写入数据的程执行完毕之后,将flag变为true时,读锁才可以进入读取的方法。