需求:
对于买票系统,容器中放入1000张票,开启10个线程抢票。
(1)很容易想到用加锁的办法解决线程并发问题
下面使用synchronized关键字解决
1
1
2 1public class SellTicket{
2
2
1
2 1 static List<String> tickets = new LinkedList<String>();//1.初始化票容器
2
3
1
2 1
2
4
1
2 1 static{
2
5
1
2 1 for(int i=0;i<1000;i++) tickets.add("第" + i + "张票");//2.往容器中放1000张票
2
6
1
2 1 }
2
7
1
2 1 public static void main(String[] args){
2
8
1
2 1 for(int i=0;i<10;i++){//3.开启10个线程抢票
2
9
1
2 1 new Thread(()->{
2
10
1
2 1 while(true){
2
11
1
2 1 synchronized(tickets){//4.使用synchronized关键字加锁保证线程安全
2
12
1
2 1 if(tickets.size() <= 0) break;
2
13
1
2 1 System.out.println("销售--" + tickets.remove(0));
2
14
1
2 1 }
2
15
1
2 1 }
2
16
1
2 1 }).start();
2
17
1
2 1 }
2
18
1
2 1 }
2
19
1
2 1}
2
用以上加锁的方式,每次抢票都锁定整个对象,导致效率非常底下。
(2)JDK 1.6开始使用并发包java.concurrent高效解决线程安全问题
采用并发队列
ConcurrentLinkedQueue作为票容器实现并发抢票
1
1
2 1public class SellTicket{
2
2
1
2 1 static Queue<String> tickets = new ConcurrentLinkedQueue<String>();//初始化并发队列容器
2
3
1
2 1 static{
2
4
1
2 1 for(int i=0;i<1000;i++) tickets.add("第" + i + "张票");//2.往容器中放1000张票
2
5
1
2 1 }
2
6
1
2 1 public static void main(String[] args){//3.开启10个线程抢票
2
7
1
2 1 for(int i=0;i<10;i++){
2
8
1
2 1 new Thread(()->{
2
9
1
2 1 while(true){
2
10
1
2 1 String ticket = tickets.poll();//4.一张张票出队列
2
11
1
2 1 if(ticket == null) break;
2
12
1
2 1 else System.out.println("销售--" + ticket);
2
13
1
2 1 }
2
14
1
2 1 }).start();
2
15
1
2 1 }
2
16
1
2 1 }
2
17
1
2 1}
2
采用不加锁的方式解决线程安全问题的核心:队列先进先出的特性、并发队列本身操作的原子性(poll完成之后不再操作队列,所以不会出线程安全问题)