单一线程池

Future<String> future = threadPool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "hello";
            }
        });

CompletionService<Integer> completionService = new ExecutorCompletionService<~>(threadPool2);
        for (int i = 0; i < 10; i++) {
            final int seq = i;
            completionService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    Thread.sleep(new Random().nextInt(5000));
                    return seq;
                }
            });
        }

线程间通讯

  1. AtomicInteger类:能够对中央数据/数组中的基本数据/类中的基本数据进行操作
  2. Executors类:
    a. ExecutorService threadPool =
    Executors.newFixedThreadPool(3);固定大小线程池
    b. ExecutorService threadPool =
    Executors.newCachedThreadPool();缓存线程池
    c. ExecutorService threadPool =
    Executors.newSingleThreadExecutor();单一线程池
  3. Callable&Future:
    a.
    Callable采纳ExecutorService的submit方法提交,重返的future对象能够裁撤义务
    b.
    Future取得的结果类型和Callable重返的结果类型必须一致,通过泛型来兑现

线程安全

1.
线程安全:当多少个线程访问某四个类(对象或方法)时,这些类(对象或措施)始终能显现出科学的行事,那么那些类(对象或格局)正是线程安全的。

2.
线程不安全的演示。期望结果是一千00,实际却不是,并且每回执行结果只怕两样。

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class Test {
 5 
 6     public static void main(String[] args) throws Exception {
 7         MyNumber myNumber = new MyNumber();
 8         List<MyThread> myThreads = new ArrayList<>();
 9         for (int index = 0; index < 100; index++) {
10             MyThread myThread = new MyThread(myNumber);
11             myThreads.add(myThread);
12             myThread.start();
13         }
14         for (MyThread myThread : myThreads) {
15             myThread.join();
16         }
17         System.out.println(myNumber.value());
18     }
19 
20 }
21 
22 class MyNumber {
23     
24     private int n = 0;
25     
26     public int value() {
27         return n;
28     }
29     
30     public void increate() {
31         n = n + 1;
32     }
33     
34 }
35 
36 class MyThread extends Thread {
37     
38     private MyNumber myNumber;
39     
40     public MyThread(MyNumber myNumber) {
41         this.myNumber = myNumber;
42     }
43     
44     @Override
45     public void run() {
46         try {
47             sleep(3000);
48         } catch (InterruptedException e) {
49             e.printStackTrace();
50         }
51         
52         for (int index = 0; index < 1000; index++) {
53             myNumber.increate();
54         }
55     }
56     
57 }
  1. 协办集合【java5提供的】
    a. ConcurrentHashMap
    b. ConcurrentSkipListMap
    c. ConcurrentSkipListSet
    d. CopyOnWriteArrayList
    e. CopyOnWriteArraySet

  2. 应用了多少个condition!!!

Exchanger

1.
java.util.concurrent.Exchanger可实现四个线程间的数码交互。先执行Exchanger.exchange()方法的线程被封堵,直到另一个线程也执行Exchanger.exchange()方法才打住,两条线程交流完数据后继续执行。

  1. 示例。

    1 import java.util.Random;
    2 import java.util.UUID;
    3 import java.util.concurrent.Exchanger;
    4
    5 public class Test {
    6
    7 public static void main(String[] args) {
    8 Exchanger exchanger = new Exchanger();
    9 new MyThread(exchanger).start();
    10 new MyThread(exchanger).start();
    11 }
    12
    13 }
    14
    15 class MyThread extends Thread {
    16
    17 private Exchanger exchanger;
    18
    19 public MyThread(Exchanger exchanger) {
    20 this.exchanger = exchanger;
    21 }
    22
    23 @Override
    24 public void run() {
    25 String value = UUID.randomUUID().toString();
    26 System.out.println(Thread.currentThread().getName() + “准备用” + value + “沟通。”);
    27 String newValue = null;
    28 try {
    29 Thread.sleep(new Random().nextInt(五千));
    30 newValue = exchanger.exchange(value);
    31 } catch (InterruptedException e) {
    32 e.printStackTrace();
    33 }
    34 System.out.println(Thread.currentThread().getName() + “沟通得到” + newValue + “。”);
    35 }
    36
    37 }

线程安全的贯彻格局

线程池

  1. 线程池优点:

    a)
下跌资源消耗:通过重复利用已创立的线程降低线程成立和销毁造成的损耗。

    b)
进步响应速度:当任务到达时,职务能够不必要等到线程创立就能登时施行。

    c)
升高线程的可管理性:线程是稀缺资源,假诺无界定的创设,不仅会开销系统财富,还会下降系统的安静,使用线程池能够开始展览联合的分配,调优和督察。

  1. 多种线程池:

    a) 固定大小线程池:Executors.newFixedThreadPool(int nThreads)。

    b)
缓存线程池:Executors.newCachedThreadPool(),线程池大小随提交职分数大增而充实。

    c) 单一线程池:Executors.newSingleThreadExecutor()。

    d) 调度线程池:Executors.newScheduledThreadPool(int
corePoolSize),调度执行线程。

  1. 关闭线程池:

    a) 任务执行完成后关门:ExecutorService.shutdown()。

    b) 不论职分是还是不是成功即刻关闭:Executor瑟维斯.shutdownNow()。

  1. 示例。

    1 import java.util.Random;
    2 import java.util.concurrent.ExecutorService;
    3 import java.util.concurrent.Executors;
    4 import java.util.concurrent.atomic.AtomicInteger;
    5
    6 public class Test {
    7
    8 public static void main(String[] args) {
    9 ExecutorService threadPool = Executors.newFixedThreadPool(3);
    10 // ExecutorService threadPool = Executors.newCachedThreadPool();
    11 // ExecutorService threadPool = Executors.newSingleThreadExecutor();
    12 Task0 task0 = new Task0();
    13 Task1 task1 = new Task1();
    14 int taskCount = 20;
    15 for (int index = 0; index < taskCount; index++) { 16 if (index % 2 == 0) { 17 threadPool.execute(task0); 18 } else { 19 threadPool.execute(task1); 20 } 21 } 22 System.out.println(taskCount + " tasks have been committed."); 23 threadPool.shutdown(); 24 } 25 26 } 27 28 class Task0 implements Runnable { 29
    30 private AtomicInteger count = new AtomicInteger(0);
    31
    32 @Override
    33 public void run() {
    34 System.out.println(Thread.currentThread().getName() + ” is executing Task0-” + count.getAndIncrement());
    35 try {
    36 Thread.sleep(new Random().nextInt(500));
    37 } catch (InterruptedException e) {
    38 e.printStackTrace();
    39 }
    40
    41 }
    42
    43 }
    44
    45 class Task1 implements Runnable {
    46
    47 private AtomicInteger count = new AtomicInteger(0);
    48
    49 @Override
    50 public void run() {
    51 System.out.println(Thread.currentThread().getName() + ” is executing Task1-” + count.getAndIncrement());
    52 try {
    53 Thread.sleep(new Random().nextInt(500));
    54 } catch (InterruptedException e) {
    55 e.printStackTrace();
    56 }
    57 }
    58
    59 }

condition2.jpg

无同步

假设本来就不涉及共享数据,那么就无须任何共同措施,代码天生正是线程安全的。

condition.jpg

文学家进餐难题

一张圆桌上坐着 5
名文学家,桌子上每八个文学家之间摆了一根筷子,桌子的高级中学级是一碗米饭。思想家们倾注终生精力用于思考和就餐,教育家在思索时,并不影响别人。唯有当史学家饥饿的时候,才打算拿起左、右两根筷子(一根一根拿起)。若是筷子已在外人手上,则需静观其变。饥饿的思想家唯有同时拿到了两根筷子才方可起先吃饭,当用餐达成后,放下筷子继续考虑。

图片 1

  1 import java.util.Random;
  2 
  3 public class Test {
  4 
  5     public static void main(String[] args) {
  6         Table table = new Table();
  7         new Philosopher(table).start();
  8         new Philosopher(table).start();
  9         new Philosopher(table).start();
 10         new Philosopher(table).start();
 11         new Philosopher(table).start();
 12     }
 13 
 14 }
 15 
 16 class Chopstick {
 17     
 18     private static int count;
 19     
 20     private int id;
 21     
 22     private boolean isTakenUp;
 23     
 24     public Chopstick() {
 25         id = count++;
 26     }
 27     
 28     public boolean isTakenUp() {
 29         return isTakenUp;
 30     }
 31 
 32     public void setTakenUp(boolean isTakenUp) {
 33         this.isTakenUp = isTakenUp;
 34     }
 35 
 36     @Override
 37     public String toString() {
 38         return "Chopstick-" + id;
 39     }
 40     
 41 }
 42 
 43 class Table {
 44     
 45     private static final int CAPACITY = 5;
 46     
 47     private Chopstick[] chopsticks = new Chopstick[CAPACITY];
 48     
 49     public Table() {
 50         for (int index = 0; index < chopsticks.length; index++) {
 51             chopsticks[index] = new Chopstick();
 52         }
 53     }
 54     
 55     public synchronized void takeUp(int leftChopstickIndex, int rightChopstickIndex) {
 56         Chopstick leftChopstick = chopsticks[leftChopstickIndex];
 57         Chopstick rightChopstick = chopsticks[rightChopstickIndex];
 58         while (leftChopstick.isTakenUp() || rightChopstick.isTakenUp()) {
 59             try {
 60                 wait();
 61             } catch (InterruptedException e) {
 62                 e.printStackTrace();
 63             }
 64         }
 65         leftChopstick.setTakenUp(true);
 66         System.out.println(leftChopstick + " has been taken up.");
 67         rightChopstick.setTakenUp(true);
 68         System.out.println(rightChopstick + " has been taken up.");
 69         notifyAll();
 70     }
 71     
 72     public synchronized void putDown(int leftChopstickIndex, int rightChopstickIndex) {
 73         Chopstick leftChopstick = chopsticks[leftChopstickIndex];
 74         Chopstick rightChopstick = chopsticks[rightChopstickIndex];
 75         leftChopstick.setTakenUp(false);
 76         System.out.println(leftChopstick + " has been put down.");
 77         rightChopstick.setTakenUp(false);
 78         System.out.println(rightChopstick + " has been put down.");
 79         notifyAll();
 80     }
 81     
 82 }
 83 
 84 class Philosopher extends Thread {
 85     
 86     private static final int MAX_COUNT = 5;
 87     
 88     private static int count;
 89     
 90     private int id;
 91     
 92     private Table table;
 93     
 94     public Philosopher(Table table) {
 95         if (count >= MAX_COUNT) {
 96             throw new RuntimeException("Cannot create Philosopher instance more than " + MAX_COUNT + ".");
 97         }
 98         id = count++;
 99         setName("Philosopher-" + id);
100         this.table = table;
101     }
102 
103     @Override
104     public void run() {
105         final int leftChopstickIndex = id;
106         final int rightChopstickIndex = (id + 1) % MAX_COUNT;
107         while (true) {
108             table.takeUp(leftChopstickIndex, rightChopstickIndex);
109             System.out.println(getName() + " is eating.");
110             
111             try {
112                 Thread.sleep(new Random().nextInt(500));
113             } catch (InterruptedException e) {
114                 e.printStackTrace();
115             }
116             
117             System.out.println(getName() + " has eaten.");
118             table.putDown(leftChopstickIndex, rightChopstickIndex);
119             
120             try {
121                 Thread.sleep(new Random().nextInt(500));
122             } catch (InterruptedException e) {
123                 e.printStackTrace();
124             }
125         }
126     }
127     
128 }
  1. Lock&Condition
    a. 七个线程要贯彻互斥,它们必须用同二个Lock对象。
    b. Lock与synchronize功效一样,锁本身是二个对象
    c. 读写锁【三个读锁不排斥、读锁写锁互斥、写锁写锁互斥】
    d. Condition功用看似Object的wait和notify方法
    e. 二个锁能够有多个Condition,即有多路等待和通报

  2. Semaphore信号灯
    a. 能够维护当前作客本人的线程个数,并提供联合机制
    b.
    单个semaphore能够兑现互斥锁作用【一个线程得到锁,再由另一个线程释放锁】

  3. 队列BlockingQueue
    a. 唯有put方法和take方法才享有阻塞效果
    b. 用四个有着三个空中的队列来完成共同布告功用
    c.
    与Semaphore相似;但队列是一方存放数据,一方释放数据;而Semaphore经常是由同样方设置和假释信号量
    d.ArrayBlockingQueue & LinkedBlockingDeque

ReentrantLock

1.
java.util.concurrent.locks.ReentrantLock与synchronized功效类似,只是更面向对象。

  1. 留意:Lock应该与try { … } finally { … }使用,保险锁一定释放。

  2. 线程不安全示范的Lock写法。

    1 class MyNumber {
    2
    3 private Lock lock = new ReentrantLock();
    4
    5 private int n = 0;
    6
    7 public int value() {
    8 return n;
    9 }
    10
    11 public void increate() {
    12 try {
    13 lock.lock();
    14 n = n + 1;
    15 } finally {
    16 lock.unlock();
    17 }
    18 }
    19
    20 }

JDK5新功能

ReadWriteLock

1.
java.util.concurrent.locks.ReadWriteLock分包读锁和写锁,类似“读者-写者难题”中的读者和写者,即三个读锁不排外,读锁与写锁互斥,写锁与写锁互斥。

  1. “读者-写者难题”的读锁、写锁写法。

    1 import java.util.Random;
    2 import java.util.concurrent.locks.ReadWriteLock;
    3 import java.util.concurrent.locks.ReentrantReadWriteLock;
    4
    5 public class Test {
    6
    7 public static void main(String[] args) {
    8 File file = new File();
    9 new Reader(file).start();
    10 new Reader(file).start();
    11 new Reader(file).start();
    12 new Writer(file).start();
    13 new Writer(file).start();
    14 }
    15
    16 }
    17
    18 class File {
    19
    20 private ReadWriteLock lock = new ReentrantReadWriteLock();
    21
    22 public void beginRead() {
    23 lock.readLock().lock();
    24 }
    25
    26 public void endRead() {
    27 lock.readLock().unlock();
    28 }
    29
    30 public void beginWrite() {
    31 lock.writeLock().lock();
    32 }
    33
    34 public void endWrite() {
    35 lock.writeLock().unlock();
    36 }
    37
    38 }
    39
    40 class Reader extends Thread {
    41
    42 private static int count;
    43
    44 private File file;
    45
    46 public Reader(File file) {
    47 super(“Reader-” + count++);
    48 this.file = file;
    49 }
    50
    51 @Override
    52 public void run() {
    53 while (true) {
    54 try {
    55 file.beginRead();
    56 System.out.println(Thread.currentThread().getName() + ” is reading.”);
    57
    58 try {
    59 Thread.sleep(new Random().nextInt(500));
    60 } catch (InterruptedException e) {
    61 e.printStackTrace();
    62 }
    63
    64 System.out.println(Thread.currentThread().getName() + ” has read.”);
    65 } finally {
    66 file.endRead();
    67 }
    68
    69 try {
    70 Thread.sleep(new Random().nextInt(500));
    71 } catch (InterruptedException e) {
    72 e.printStackTrace();
    73 }
    74 }
    75 }
    76
    77 }
    78
    79 class Writer extends Thread {
    80
    81 private static int count;
    82
    83 private File file;
    84
    85 public Writer(File file) {
    86 super(“Writer-” + count++);
    87 this.file = file;
    88 }
    89
    90 @Override
    91 public void run() {
    92 while (true) {
    93 try {
    94 file.beginWrite();
    95 System.out.println(Thread.currentThread().getName() + ” is writing.”);
    96
    97 try {
    98 Thread.sleep(new Random().nextInt(500));
    99 } catch (InterruptedException e) {
    100 e.printStackTrace();
    101 }
    102
    103 System.out.println(Thread.currentThread().getName() + ” has wroten.”);
    104 } finally {
    105 file.endWrite();
    106 }
    107
    108 try {
    109 Thread.sleep(new Random().nextInt(500));
    110 } catch (InterruptedException e) {
    111 e.printStackTrace();
    112 }
    113 }
    114 }
    115
    116 }

3.
施用ReadWriteLock优化缓存:第3个线程写,后续线程只读(类似ReentrantReadWriteLock
JDK文书档案中的示例)。

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 import java.util.Random;
 4 import java.util.concurrent.locks.ReadWriteLock;
 5 import java.util.concurrent.locks.ReentrantReadWriteLock;
 6 
 7 class Cache {
 8     
 9     private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
10     
11     private Map<Object, Object> data = new HashMap<>();
12     
13     public Object getValue(Object key) {
14         readWriteLock.readLock().lock();
15         Object value = null;
16         try {
17             value = data.get(key);
18             if (value == null) {
19                 readWriteLock.readLock().unlock();
20                 readWriteLock.writeLock().lock();
21                 try {
22                     if (value == null) {
23                         value = new Random().nextInt(1000);    // 模拟去数据库查询数据
24                     }
25                 } finally {
26                     readWriteLock.writeLock().unlock();
27                 }
28                 readWriteLock.readLock().lock();
29             }
30             
31         } finally {
32             readWriteLock.readLock().unlock();
33         }
34         return value;
35     }
36     
37 }

Condition

1.
java.util.concurrent.locks.Condition近乎Object.wait()和Object.notify()/Object.notifyAll()方法,实现了线程间通讯。

  1. “子线程、主线程交替循环”面试题的Condition写法。

    1 class Looper {
    2
    3 private Lock lock = new ReentrantLock();
    4
    5 private Condition condition = lock.newCondition();
    6
    7 private boolean runSub = true;
    8
    9 public void sub() {
    10 for (int i = 0; i < 50; i++) { 11 lock.lock(); 12 try { 13 while (!runSub) { 14 try { 15 condition.await(); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 for (int j = 0; j < 10; j++) { 21 System.out.println("子线程第" + i + "次巡回" + j + "。"); 22 } 23 runSub = false; 24 condition.signal(); 25 } finally { 26 lock.unlock(); 27 } 28 } 29 } 30
    31 public void main() {
    32 for (int i = 0; i < 50; i++) { 33 lock.lock(); 34 try { 35 while (runSub) { 36 try { 37 condition.await(); 38 } catch (InterruptedException e) { 39 e.printStackTrace(); 40 } 41 } 42 for (int j = 0; j < 100; j++) { 43 System.out.println("主线程第" + i + "次巡回" + j + "。"); 44 } 45 runSub = true; 46 condition.signal(); 47 } finally { 48 lock.unlock(); 49 } 50 } 51 } 52
    53 }

3.
与Object.wait()和Object.notify差别的是,Condition能完成多路暂停和提醒,具体示例参考Condition
JDK文书档案。

劳动者-消费者难题

一组生产者进度和一组消费者进程共享一个初叶为空、大小为 n
的缓冲区,惟有缓冲区没满时,生产者才能把新闻放入到缓冲区,不然必须等待;唯有缓冲区不空时,消费者才能从中取出音信,不然必须等待。由于缓冲区是逼近能源,它只同意三个劳动者放入音讯,或许二个顾客从中取出消息。

  1 import java.util.Random;
  2 import java.util.concurrent.atomic.AtomicInteger;
  3 
  4 public class Test {
  5 
  6     public static void main(String[] args) {
  7         Container container = new Container();
  8         new Producer(container).start();
  9         new Producer(container).start();
 10         new Producer(container).start();
 11         new Consumer(container).start();
 12         new Consumer(container).start();
 13     }
 14 
 15 }
 16 
 17 class Product {
 18     
 19     private static final AtomicInteger COUNT = new AtomicInteger(0);
 20     
 21     private int id;
 22     
 23     public Product() {
 24         id = COUNT.getAndIncrement();
 25     }
 26     
 27     @Override
 28     public String toString() {
 29         return "Product-" + id;
 30     }
 31     
 32 }
 33 
 34 class Container {
 35     
 36     private final static int CAPACITY = 10;
 37     
 38     private Product[] products = new Product[CAPACITY];
 39     
 40     private int size;
 41     
 42     public synchronized void push(Product product) {
 43         while (size >= CAPACITY) {
 44             try {
 45                 wait();
 46             } catch (InterruptedException e) {
 47                 e.printStackTrace();
 48             }
 49         }
 50         products[size] = product;
 51         size++;
 52         notify();
 53     }
 54     
 55     public synchronized Product pop() {
 56         while (size <= 0) {
 57             try {
 58                 wait();
 59             } catch (InterruptedException e) {
 60                 e.printStackTrace();
 61             }
 62         }
 63         size--;
 64         Product product = products[size];
 65         notify();
 66         return product;
 67     }
 68     
 69 }
 70 
 71 class Producer extends Thread {
 72     
 73     private static int count;
 74     
 75     private Container container;
 76     
 77     public Producer(Container container) {
 78         super("Producer-" + count++);
 79         this.container = container;
 80     }
 81     
 82     @Override
 83     public void run() {
 84         while (true) {
 85             Product product = new Product();
 86             System.out.println(getName() + " produced " + product);
 87             container.push(product);
 88             
 89             try {
 90                 Thread.sleep(new Random().nextInt(500));
 91             } catch (InterruptedException e) {
 92                 e.printStackTrace();
 93             }
 94         }
 95     }
 96     
 97 }
 98 
 99 class Consumer extends Thread {
100     
101     private static int count;
102     
103     private Container container;
104     
105     public Consumer(Container container) {
106         super("Consumer-" + count++);
107         this.container = container;
108     }
109     
110     @Override
111     public void run() {
112         while (true) {
113             Product product = container.pop();
114             System.out.println(getName() + " consumed " + product);
115             
116             try {
117                 Thread.sleep(new Random().nextInt(500));
118             } catch (InterruptedException e) {
119                 e.printStackTrace();
120             }
121         }
122     }
123     
124 }

线程内共享

1.
ThreadLocal存放的值是线程内共享的,线程间互斥的。重要用于线程内共享数据,防止通过参数来传递,那样能优雅地缓解一些实在难题。

2.
ThreadLocal的规律是为每贰个线程都提供了变量的副本,使得种种线程在某暂且间访问到的并不是同多个指标。

  1. 数据库连接工具类的比方。

    1 import java.sql.Connection;
    2 import java.sql.DriverManager;
    3 import java.sql.SQLException;
    4
    5 public class ConnectionUtils {
    6
    7 private static ThreadLocal threadLocalConnection = new ThreadLocal();
    8
    9 public static Connection getCurrent() throws SQLException {
    10 Connection connection = threadLocalConnection.get();
    11 if (connection == null || connection.isClosed()) {
    12 connection = DriverManager.getConnection(“…”);
    13 threadLocalConnection.set(connection);
    14 }
    15 return connection;
    16 }
    17
    18 public static void close() throws SQLException {
    19 Connection connection = threadLocalConnection.get();
    20 if (connection != null && !connection.isClosed()) {
    21 connection.close();
    22 threadLocalConnection.remove();
    23 }
    24 }
    25
    26 }

BlockingQueue

1.
java.util.concurrent.BlockingQueue为阻塞队列,类似“生产者-消费者难题”中的容器,“满值欲加”和“无值欲取”都会被封堵。

  1. 查JDK文书档案可见:

                                 场景+操作

结果

“满值欲加”

“无值欲取”

检查

抛出异常

add(e)

remove()

element()

返回值

offer(e)

poll()

peek()

阻塞

put(e)

take()

不可用

3.
稳定长度阻塞队列ArrayBlockingQueue,不定点长度阻塞队列LinkedBlockingDeque。

  1. “生产者-消费者难点”的BlockingQueue写法。

    1 class Container {
    2
    3 private final static int CAPACITY = 10;
    4
    5 private BlockingQueue blocingQueue = new ArrayBlockingQueue(CAPACITY);
    6
    7 public void push(Product product) {
    8 try {
    9 blocingQueue.put(product);
    10 } catch (InterruptedException e) {
    11 e.printStackTrace();
    12 }
    13 }
    14
    15 public Product pop() {
    16 Product product = null;
    17 try {
    18 product = blocingQueue.take();
    19 } catch (InterruptedException e) {
    20 e.printStackTrace();
    21 }
    22 return product;
    23 }
    24
    25 }

5.
七个拥有一个体积的不通队列可实现线程间通讯。“子线程、主线程交替循环难点”的BlockingQueue写法。

 1 class Looper {
 2     
 3     private BlockingQueue<Integer> subBlockingQueue = new ArrayBlockingQueue<Integer>(1);
 4     
 5     private BlockingQueue<Integer> mainBlockingQueue = new ArrayBlockingQueue<Integer>(1);
 6     
 7     public Looper() {
 8         subBlockingQueue.add(1);
 9     }
10     
11     public void sub() {
12         for (int i = 0; i < 50; i++) {
13             try {
14                 subBlockingQueue.take();
15             } catch (InterruptedException e) {
16                 e.printStackTrace();
17             }
18             for (int j = 0; j < 10; j++) {
19                 System.out.println("子线程第" + i + "次循环" + j + "。");
20             }
21             mainBlockingQueue.add(1);
22         }
23     }
24     
25     public void main() {
26         for (int i = 0; i < 50; i++) {
27             try {
28                 mainBlockingQueue.take();
29             } catch (InterruptedException e) {
30                 e.printStackTrace();
31             }
32             for (int j = 0; j < 100; j++) {
33                 System.out.println("主线程第" + i + "次循环" + j + "。");
34             }
35             subBlockingQueue.add(1);
36         }
37     }
38     
39 }

volatile关键字

  1. volatile关键字的首要功效是使变量在多个线程间可知。

2.
各样线程都会有一块工作内部存款和储蓄器区,当中存放着全数线程共享的主内部存款和储蓄器中的变量值的正片。当线程执行时,它在祥和的做事内部存款和储蓄器区中操作这个变量。为了存取共享变量,线程平日先取得锁定并去排除它的办事内部存款和储蓄器区,把那几个共享变量从具无线程的劳作内部存款和储蓄器区中国科高校学的装入个中,当线程解锁时保证该工作内部存款和储蓄器区中的值写回到共享内部存款和储蓄器中。volatile的功效正是挟持线程到主内部存款和储蓄器(共享内部存款和储蓄器)去读取变量,而不去线程工作内部存款和储蓄器区读取。

 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4         MyThread myThread = new MyThread();
 5         myThread.start();
 6         try {
 7             Thread.sleep(3000);
 8         } catch (InterruptedException e) {
 9             e.printStackTrace();
10         }
11         myThread.run = false;
12         System.out.println(myThread.run);
13     }
14 
15 }
16 
17 class MyThread extends Thread {
18     
19     public volatile boolean run = true;
20     
21     @Override
22     public void run() {
23         while (run) {
24             // running
25         }
26         System.out.println(Thread.currentThread().getName() + " stoped.");
27     }
28     
29 }

3.
volatile纵然保障了八个线程间的可见性,但不持有同步性。只可以算轻量级的synchronized,品质要比synchronized强很多,不会促成堵塞。上1个线程不安全示范用如下格局无法保险结果正确。

 1 class MyNumber {
 2     
 3     private volatile int n = 0;// 错误代码
 4     
 5     public int value() {
 6         return n;
 7     }
 8     
 9     public void increate() {
10         n = n + 1;
11     }
12     
13 }

定时器

  1. 定时器使用JDK的Timer和TimerTask;

  2. 复杂的定时器可考虑动用Quartz框架。

    1 import java.util.Timer;
    2 import java.util.TimerTask;
    3
    4 public class Test {
    5
    6 public static void main(String[] args) {
    7 new Timer().schedule(new MyTimerTask(), 3000);;
    8 }
    9
    10 }
    11
    12 class MyTimerTask extends TimerTask {
    13
    14 @Override
    15 public void run() {
    16 System.out.println(“Hello World.”);
    17 }
    18
    19 }

目录

· 线程安全

· 线程安全的兑现方式

    · 互斥同步

    · 非阻塞同步

    · 无同步

· volatile关键字

· 线程间通讯

    · Object.wait()方法%E6%96%B9%E6%B3%95)

    · Object.notify()方法%E6%96%B9%E6%B3%95)

    · 编写线程间通讯代码的老路

    · 面试题:子线程、主线程交替循环

    · 劳动者-消费者难点

    · 国学家进餐难题

    · 读者-写者难题

· 线程内共享

· 定时器

· JDK5新功能

    · 线程池

    · Callable和Future

    · ReentrantLock

    · ReadWriteLock

    · Condition

    · Semaphore

    · CyclicBarrier

    · CountDownLatch

    · Exchanger

    · BlockingQueue

    · 出现集合

· 系统峰值评估

    · 峰值参数

    · 评估办法


Semaphore

  1. java.util.concurrent.Semaphore信号量可决定同时做客能源的线程个数。

2.
Semaphore能够由二个线程获得锁,而由另1个线程释放锁,那足以使用与死锁恢复生机的风貌。

  1. Semaphore适合做网站流量控制,得到信号量的线程能够进来,不然只好等待。

  2. 示例。

    1 import java.util.concurrent.ExecutorService;
    2 import java.util.concurrent.Executors;
    3 import java.util.concurrent.Semaphore;
    4
    5 public class Test {
    6
    7 public static void main(String[] args) {
    8 ExecutorService threadPool = Executors.newCachedThreadPool();
    9 Semaphore semaphore = new Semaphore(3);
    10 Task task = new Task(semaphore);
    11 for (int index = 0; index < 10; index++) { 12 threadPool.execute(task); 13 } 14 threadPool.shutdown(); 15 } 16 17 } 18 19 class Task implements Runnable { 20
    21 private Semaphore semaphore;
    22
    23 public Task(Semaphore semaphore) {
    24 this.semaphore = semaphore;
    25 }
    26
    27 @Override
    28 public void run() {
    29 try {
    30 semaphore.acquire();
    31 System.out.println(semaphore.availablePermits() + ” permit(s) left.”);
    32 Thread.sleep(1000);
    33 System.out.println(Thread.currentThread().getId() + ” is done.”);
    34
    35 } catch (InterruptedException e) {
    36 e.printStackTrace();
    37 } finally {
    38 semaphore.release();
    39 }
    40 }
    41
    42 }

读者-写者难点

有读者和写者两组并发线程,共享三个文件,当多个或以上的读线程同时访问共享数据时不会发生副功能,但若某些写线程和其他线程(读线程或写线程)同时访问共享数据时则恐怕导致数据不一样的一无可取。由此供给:

  1. 允许五个读者能够而且对文件实行读操作;

  2. 只同意3个写者往文件中写信息;

  3. 任一写者在做到写操作以前不相同意任何读者或写者工作;

  4. 写者执行写操作前,应让已部分读者和写者全体脱离。

    1 import java.util.HashMap;
    2 import java.util.Map;
    3 import java.util.Random;
    4
    5 public class Test {
    6
    7 public static void main(String[] args) {
    8 File file = new File();
    9 new Reader(file).start();
    10 new Reader(file).start();
    11 new Reader(file).start();
    12 new Writer(file).start();
    13 new Writer(file).start();
    14 }
    15
    16 }
    17
    18 class File {
    19
    20 public enum Status {
    21 idle, reading, writing,
    22 }
    23
    24 private Map threadStatuses = new HashMap<>();
    25
    26 public synchronized void beginRead() {
    27 outer: while (true) {
    28 for (Status status : threadStatuses.values()) {
    29 if (Status.writing.equals(status)) {
    30 try {
    31 wait();
    32 } catch (InterruptedException e) {
    33 e.printStackTrace();
    34 }
    35 continue outer;
    36 }
    37 }
    38 break;
    39 }
    40 threadStatuses.put(Thread.currentThread().getId(), Status.reading);
    41 notifyAll();
    42 }
    43
    44 public synchronized void endRead() {
    45 threadStatuses.put(Thread.currentThread().getId(), Status.idle);
    46 notifyAll();
    47 }
    48
    49 public synchronized void beginWrite() {
    50 outer: while (true) {
    51 for (Status status : threadStatuses.values()) {
    52 if (!Status.idle.equals(status)) {
    53 try {
    54 wait();
    55 } catch (InterruptedException e) {
    56 e.printStackTrace();
    57 }
    58 continue outer;
    59 }
    60 }
    61 break;
    62 }
    63 threadStatuses.put(Thread.currentThread().getId(), Status.writing);
    64 notifyAll();
    65 }
    66
    67 public synchronized void endWrite() {
    68 threadStatuses.put(Thread.currentThread().getId(), Status.idle);
    69 notifyAll();
    70 }
    71
    72 }
    73
    74 class Reader extends Thread {
    75
    76 private static int count;
    77
    78 private File file;
    79
    80 public Reader(File file) {
    81 super(“Reader-” + count++);
    82 this.file = file;
    83 }
    84
    85 @Override
    86 public void run() {
    87 while (true) {
    88 file.beginRead();
    89 System.out.println(Thread.currentThread().getName() + ” is reading.”);
    90
    91 try {
    92 Thread.sleep(new Random().nextInt(500));
    93 } catch (InterruptedException e) {
    94 e.printStackTrace();
    95 }
    96
    97 System.out.println(Thread.currentThread().getName() + ” has read.”);
    98 file.endRead();
    99
    100 try {
    101 Thread.sleep(new Random().nextInt(500));
    102 } catch (InterruptedException e) {
    103 e.printStackTrace();
    104 }
    105 }
    106 }
    107
    108 }
    109
    110 class Writer extends Thread {
    111
    112 private static int count;
    113
    114 private File file;
    115
    116 public Writer(File file) {
    117 super(“Writer-” + count++);
    118 this.file = file;
    119 }
    120
    121 @Override
    122 public void run() {
    123 while (true) {
    124 file.beginWrite();
    125 System.out.println(Thread.currentThread().getName() + ” is writing.”);
    126
    127 try {
    128 Thread.sleep(new Random().nextInt(500));
    129 } catch (InterruptedException e) {
    130 e.printStackTrace();
    131 }
    132
    133 System.out.println(Thread.currentThread().getName() + ” has wroten.”);
    134 file.endWrite();
    135
    136 try {
    137 Thread.sleep(new Random().nextInt(500));
    138 } catch (InterruptedException e) {
    139 e.printStackTrace();
    140 }
    141 }
    142 }
    143
    144 }

系统峰值评估

非阻塞同步

  1. 互斥同步属于悲观并发策略,非阻塞同步属于乐观并发策略。

2.
即先行操作,如若没有任何线程争用共享数据,那么算操作成功;假设共享数据有争用,发生争论,那么再利用此外补给格局(最广泛的就是频频重试,直到成功结束)。由于并非挂起线程,所以是非阻塞的。

3.
java.util.concurrent.atomic.*包下的原子类正是以此规律,大旨操作是CAS(Compare
and set,利用x86 CPU的CMPXCHG原子指令实现),具体由sun.misc.Unsafe达成。

4.
java.util.concurrent.atomic.*包(JDK5从此)下的原子类分4组(常用已高亮):

    a) AtomicBoolean、AtomicInteger、AtomicLong,线程安全的主导类型的原子性操作。

    b)
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray,线程安全的数组类型的原子性操作,操作的不是任何数组,而是数组中的单个成分。

    c)
AtomicLongFieldUpdater、AtomicIntegerFieldUpdater、AtomicReferenceFieldUpdater,基于反射原理对象中的基本类型(长整型、整型和引用类型)举办线程安全的操作。

    d) AtomicReference、Atomic马克ableReference、AtomicStampedReference,线程安全的引用类型及防护ABA难题的引用类型的原子操作。

  1. 线程不安全示范的不封堵解决办法如下。

    1 class MyNumber {
    2
    3 private AtomicInteger n = new AtomicInteger(0);
    4
    5 public int value() {
    6 return n.get();
    7 }
    8
    9 public void increate() {
    10 n.addAndGet(1);
    11 }
    12
    13 }

  2. 参考资料:

    a) http://www.cnblogs.com/nullzx/p/4967931.html

    b) http://zl198751.iteye.com/blog/1848575

    c) http://www.cnblogs.com/Mainz/p/3546347.html

编写线程间通讯代码的老路

是因为实施instance.wait()和instance.notify()方法都必须先synchronized
(instance),所以那五个法子应写在2个类中。

1 public class ExclusiveResource {    // 互斥资源
2     public synchronized void holdAndUse() {
3         while (<check resource>) {    // 检查是否可占用资源,否则等待
4             wait();
5         }
6         // 执行占用资源后的代码
7         notify();
8     }
9 }

互斥同步

  1. 最基本互斥同步手段是synchronized关键字。

  2. 譬如,上多少个线程不安全示范的化解办法如下,三种艺术等价,都是对脚下指标加锁。

    1 public synchronized void increate() {
    2 n = n + 1;
    3 }

    1 public void increate() {
    2 synchronized (this) {
    3 n = n + 1;
    4 }
    5 }

3.
synchronized重庆大学字是二个重量级操作,因为Java线程是炫耀到操作系统原生线程上的,要是要阻塞或提醒线程,都亟需操作系统完成,那么线程要求从用户态转换成大旨态,状态转换会消耗过多的CPU时间。

  1. 外加注意,“static synchronized”方法与“synchronized (MyClass.class)
    {…}”等价,都以对类的字节对象加锁。

面试题:子线程、主线程交替循环

子线程循环拾壹次,接着主线程循环玖十六回,接着又赶回子线程循环11次,接着再回到主线程有循环100遍,如此循环伍拾遍。

 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4         System.out.println("--------");
 5         
 6         Looper looper = new Looper();
 7         SubThread subThread = new SubThread(looper);
 8         subThread.start();
 9         looper.main();
10     }
11 
12 }
13 
14 class SubThread extends Thread {
15     
16     private Looper looper;
17     
18     public SubThread(Looper looper) {
19         this.looper = looper;
20     }
21     
22     @Override
23     public void run() {
24         looper.sub();
25     }
26     
27 }
28 
29 class Looper {
30     
31     private boolean runSub = true;
32     
33     public void sub() {
34         for (int i = 0; i < 50; i++) {
35             synchronized (this) {
36                 while (!runSub) {
37                     try {
38                         wait();
39                     } catch (InterruptedException e) {
40                         e.printStackTrace();
41                     }
42                 }
43                 for (int j = 0; j < 10; j++) {
44                     System.out.println("子线程第" + i + "次循环" + j + "。");
45                 }
46                 runSub = false;
47                 notify();
48             }
49         }
50     }
51     
52     public void main() {
53         for (int i = 0; i < 50; i++) {
54             synchronized (this) {
55                 while (runSub) {
56                     try {
57                         wait();
58                     } catch (InterruptedException e) {
59                         e.printStackTrace();
60                     }
61                 }
62                 for (int j = 0; j < 100; j++) {
63                     System.out.println("主线程第" + i + "次循环" + j + "。");
64                 }
65                 runSub = true;
66                 notify();
67             }
68         }
69     }
70     
71 }

Object.notify()方法

1.
提醒执行了instance.wait()方法的线程。若是存在七个那样的线程,则任意唤醒三个。

2.
当前线程必须先对该对象instance加锁(即synchronized)才可调用instance.notify()方法,不然抛出很是IllegalMonitorStateException。

  1. 综上两点所述,套路如下。

    1 synchronized (instance) {
    2 instance.notify();
    3 }

4.
Object.notifyAll()方法与Object.notify()方法类似,差异是只要存在三个等待的线程,则全体唤起。

Object.wait()方法

1.
使实践instance.wait()方法的脚下线程暂停,直至调用该对象instance.notify()或instance.notifyAll()方法唤醒该线程。

2.
当前线程必须先对该对象instance加锁(即synchronized)才可调用instance.wait()方法,否则抛出极度IllegalMonitorStateException。

  1. 或然存在刹车和虚唤醒,所以一般在循环中履行instance.wait()方法。

  2. 综上三点所述,套路如下。

    1 synchronized (instance) {
    2 while (判断是或不是可占用能源) {
    3 instance.wait();
    4 }
    5 }

5.
只顾Object.wait()方法与Thread.sleep()方法的区别:wait()方法暂停时会释放synchronized的财富,而sleep()方法不会。

评估情势

1.
一般通过支付、运转、测试以及业务等有关人士,综合出种类的一多元阀值,然后依据重点阀值(如QPS、兰德EvoqueT等)对系统举办中用改观。

2.
展开多轮压力测试之后,能够对系统实行峰值评估,选择80/20规则,即八成的PV将在伍分之一的光阴内完成。那样测算出系列峰值QPS:

峰值QPS = ( 总PV * 80% ) / ( 60 * 60 * 24 * 20% )

总峰值QPS除以单台机器所能承受的参天QPS正是必须的机器数量:

机器数 = 总峰值QPS / 压测得出的单机极限QPS

还要考虑大型减价活动和双十壹 、双十二吃香事件、遭逢DDoS攻击等处境,系统的付出和护卫人必要了然当前系统运维的情事和负载境况。

 

作者:netoxi
出处:http://www.cnblogs.com/netoxi
本文版权归小编和博客园共有,欢迎转载,未经同意须保留此段注明,且在篇章页面分明地点给出原作连接。欢迎指正与交换。

 

CountDownLatch

1.
java.util.concurrent.CountDownLatch尾数器,执行CountDownLatch.countDown()计数器减1,当计数器为0时,则兼具等待的线程结束阻塞。

2.
可完结四个线程等待七个线程,也可达成多个线程等待一个线程。以一个选手、3个裁定发令并总括结果为示范。

 1 import java.util.Random;
 2 import java.util.concurrent.CountDownLatch;
 3 
 4 public class Test {
 5 
 6     public static void main(String[] args) {
 7         CountDownLatch beginCountDownLatch = new CountDownLatch(1);
 8         CountDownLatch endCountDownLatch = new CountDownLatch(3);
 9         new Runner(beginCountDownLatch, endCountDownLatch).start();
10         new Runner(beginCountDownLatch, endCountDownLatch).start();
11         new Runner(beginCountDownLatch, endCountDownLatch).start();
12         new Judge(beginCountDownLatch, endCountDownLatch).start();
13     }
14 
15 }
16 
17 class Runner extends Thread {
18     
19     private CountDownLatch beginCountDownLatch;
20     
21     private CountDownLatch endCountDownLatch;
22     
23     public Runner(CountDownLatch beginCountDownLatch, CountDownLatch endCountDownLatch) {
24         this.beginCountDownLatch = beginCountDownLatch;
25         this.endCountDownLatch = endCountDownLatch;
26     }
27 
28     @Override
29     public void run() {
30         try {
31             System.out.println("Runner " + getId() + " is ready.");
32             beginCountDownLatch.await();
33             Thread.sleep(new Random().nextInt(500));
34             System.out.println("Runner " + getId() + " has run.");
35             endCountDownLatch.countDown();
36         } catch (InterruptedException e) {
37             e.printStackTrace();
38         }
39     }
40     
41 }
42 
43 class Judge extends Thread {
44     
45     private CountDownLatch beginCountDownLatch;
46     
47     private CountDownLatch endCountDownLatch;
48     
49     public Judge(CountDownLatch beginCountDownLatch, CountDownLatch endCountDownLatch) {
50         this.beginCountDownLatch = beginCountDownLatch;
51         this.endCountDownLatch = endCountDownLatch;
52     }
53 
54     @Override
55     public void run() {
56         try {
57             Thread.sleep(3000);
58             System.out.println("Judge says \"Go!\"");
59             beginCountDownLatch.countDown();
60             System.out.println("Judge is waiting for runners.");
61             endCountDownLatch.await();
62             System.out.println("Judge has waited.");
63             
64         } catch (InterruptedException e) {
65             e.printStackTrace();
66         }
67     }
68     
69 }

峰值参数

  1. PV(Page
    View):网站的总访问量、页面浏览量或点击量,用户每刷新一次就会被记录三次。

  2. UV(Unique
    Visitor):访问网站的一台微型总结机客户端为二个访客。一般来讲,时间上以00:00至24:00之间同样IP的客户端只记录二遍。

  3. QPS(Query Per
    Second):每秒查询数。QPS极大程度上代表了系统业务上的农忙程度,每趟查询的幕后,大概对应着累累磁盘I/O,数十次网络请求,数十次CPU时间片等。通过QPS可以非凡直观的了然当前系统工作情状,一旦当前QPS超过所设定的预警阀值,能够设想扩大机械对集群扩大体量,避防压力过大导致宕机。能够依照前期的下压力测试得到估值,在组合后期综合运转意况,推测出阀值。

  4. 牧马人T(Response
    Time):请求的响应时间。那些目标相当重庆大学,间接证实前端用户的感受,任何系统设计师都想降低XC60T。

  5. 还有设计CPU、内部存储器、互连网、磁盘等景色的参数。

CyclicBarrier

1.
java.util.concurrent.CyclicBarrier阻塞一组线程,直到达到内定的封堵线程数量后才止住阻塞。类似生活中聚集的景观,10小伙伴约定地方会面,先到着等候,等清一色到齐才出发。

  1. 示例。

    1 import java.util.Random;
    2 import java.util.concurrent.BrokenBarrierException;
    3 import java.util.concurrent.CyclicBarrier;
    4 import java.util.concurrent.ExecutorService;
    5 import java.util.concurrent.Executors;
    6
    7 public class Test {
    8
    9 public static void main(String[] args) {
    10 ExecutorService threadPool = Executors.newCachedThreadPool();
    11 CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
    12 Task task = new Task(cyclicBarrier);
    13 for (int index = 0; index < 9; index++) { 14 threadPool.execute(task); 15 } 16 threadPool.shutdown(); 17 } 18 19 } 20 21 class Task implements Runnable { 22
    23 private CyclicBarrier cyclicBarrier;
    24
    25 public Task(CyclicBarrier cyclicBarrier) {
    26 this.cyclicBarrier = cyclicBarrier;
    27 }
    28
    29 @Override
    30 public void run() {
    31 try {
    32 Thread.sleep(new Random().nextInt(500));
    33 } catch (InterruptedException e) {
    34 e.printStackTrace();
    35 }
    36 System.out.println(Thread.currentThread().getName() + “执行达成。当前等待的线程个数是” + cyclicBarrier.getNumberWaiting() + “。”);
    37 try {
    38 cyclicBarrier.await();
    39 } catch (InterruptedException e) {
    40 e.printStackTrace();
    41 } catch (BrokenBarrierException e) {
    42 e.printStackTrace();
    43 }
    44 }
    45
    46 }

Callable和Future

  1. Callable接口:异步义务。

  2. Future接口:异步任务的结果。

    1 import java.util.Random;
    2 import java.util.concurrent.Callable;
    3 import java.util.concurrent.ExecutionException;
    4 import java.util.concurrent.ExecutorService;
    5 import java.util.concurrent.Executors;
    6 import java.util.concurrent.Future;
    7
    8 public class Test {
    9
    10 public static void main(String[] args) throws InterruptedException, ExecutionException {
    11 ExecutorService threadPool = Executors.newFixedThreadPool(3);
    12 Future future0 = threadPool.submit(new Task());
    13 Future future1 = threadPool.submit(new Task());
    14 System.out.println(“Two tasks have been committed.”);
    15 System.out.println(“future0=” + future0.get());
    16 System.out.println(“future1=” + future1.get());
    17 threadPool.shutdown();
    18 }
    19
    20 }
    21
    22 class Task implements Callable {
    23
    24 @Override
    25 public Integer call() throws Exception {
    26 try {
    27 Thread.sleep(new Random().nextInt(500));
    28 } catch (InterruptedException e) {
    29 e.printStackTrace();
    30 }
    31 return new Random().nextInt();
    32 }
    33
    34 }

3.
CompletionService接口:提交一组Callable职分,哪个先实行完则先回去结果。

 1 import java.util.Random;
 2 import java.util.concurrent.Callable;
 3 import java.util.concurrent.CompletionService;
 4 import java.util.concurrent.ExecutionException;
 5 import java.util.concurrent.ExecutorCompletionService;
 6 import java.util.concurrent.ExecutorService;
 7 import java.util.concurrent.Executors;
 8 import java.util.concurrent.Future;
 9 import java.util.concurrent.atomic.AtomicInteger;
10 
11 public class Test {
12 
13     public static void main(String[] args) throws InterruptedException, ExecutionException {
14         ExecutorService threadPool = Executors.newFixedThreadPool(3);
15         CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool);
16         Task task = new Task();
17         int taskCount = 10;
18         for (int index = 0; index < taskCount; index++) {
19             completionService.submit(task);
20         }
21         for (int index = 0; index < taskCount; index++) {
22             Future<Integer> future = completionService.take();
23             System.out.println("future" + index + "=" + future.get());
24         }
25         threadPool.shutdown();
26     }
27 
28 }
29 
30 class Task implements Callable<Integer> {
31     
32     private AtomicInteger count = new AtomicInteger(0);
33 
34     @Override
35     public Integer call() throws Exception {
36         int ret = count.getAndIncrement();
37         try {
38             Thread.sleep(new Random().nextInt(500));
39         } catch (InterruptedException e) {
40             e.printStackTrace();
41         }
42         return ret;
43     }
44 
45 }

出现集合

  1. 并发集合与古板集合、同步集合对应提到。

传统集合(非线程安全)

同步集合(线程安全)

并发集合(线程安全)

ArrayList

Vector

Collections.synchronizedCollection(…)

Collections.synchronizedList(…)

CopyOnWriteArrayList

Set

Collections.synchronizedSet(…)

CopyOnWriteArraySet

TreeSet

Collections.synchronizedNavigableSet(…)

Collections.synchronizedSortedSet(…)

ConcurrentSkipListSet

HashMap

Hashtable

Collections.synchronizedMap(…)

ConcurrentHashMap

TreeMap

Collections.synchronizedNavigableMap(…)

Collections.synchronizedSortedMap(…)

ConcurrentSkipListMap

  1. 出现集合与协同集合的差异。

    a) 并发集合尽量制止synchronized,提供并发性;

    b)
并发集合定义了一些出现安全的复合操作,并且保证并发环境下的迭代操作不会出错。示例如下。

 1 import java.util.ArrayList;
 2 import java.util.Iterator;
 3 import java.util.List;
 4 import java.util.Vector;
 5 import java.util.concurrent.CopyOnWriteArrayList;
 6 
 7 public class Test {
 8 
 9     public static void main(String[] args) {
10 //        List<String> list = new ArrayList<>();    // 抛出ConcurrentModificationException,或结果不正确
11 //        List<String> list = new Vector<>();    // 抛出ConcurrentModificationException,或结果不正确
12         List<String> list = new CopyOnWriteArrayList<String>();
13         list.add("s1");
14         list.add("s2");
15         list.add("s3");
16         list.add("s4");
17         list.add("s5");
18         for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
19             String current = iterator.next();
20             if ("s1".equals(current)
21                     || "s3".equals(current)
22                     || "s5".equals(current)) {
23                 list.remove(current);
24             } else {
25                 System.out.println(current);
26             }
27         }
28     }
29 
30 }

相关文章

网站地图xml地图