Java线程同步类容器和并发容器(四)

同步类容器都是线程安全的,在某些场景下,需要枷锁保护符合操作,最经典ConcurrentModifiicationException,原因是当容器迭代的过程中,被并发的修改了内容。

for (Iterator iterator = tickets.iterator(); iterator.hasNext();) {
        			String string = (String) iterator.next();
        			tickets.remove(20);
       		}

  

//多线程使用Vector或者HashTable的示例(简单线程同步问题)
public class Tickets {
    public static void main(String[] args) {
        //初始化火车票池并添加火车票:避免线程同步可采用Vector替代ArrayList  HashTable替代HashMap
        final Vector<String> tickets = new Vector<String>();

        Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

        for(int i = 1; i<= 1000; i++){
            tickets.add("火车票"+i);
        }

//        		for (Iterator iterator = tickets.iterator(); iterator.hasNext();) {
//        			String string = (String) iterator.next();
//        			tickets.remove(20);
//       		}

        for(int i = 1; i <=10; i ++){
            new Thread("线程"+i){
                public void run(){
                    while(true){
                        if(tickets.isEmpty()) break;
                        System.out.println(Thread.currentThread().getName() + "---" + tickets.remove(0));
                    }
                }
            }.start();
        }
    }
}

  同步类容器:如古老的Vector、HashTable。都是通过Collections.synchronized等工厂方法去创建实现的,底层用传统的synchronized关键字对每个共用的方法进行同步,使得每次只能有一个线程访问容器的状态。

并发类容器是专门针对并发设计的。ConCurrentHashMap替代HashTable。使用CopyOnWriteArrayList代替Voctor,CopyonWriteArraySet,并发的Queue,ConcurrentLinkedQueue高性能队列,LinkedBlockingQueue阻塞形式的队列

ConCurrentHashMap接口有两个实现

ConcurentHashMap

ConcurentSkipListMap(支持排序功能)

ConcurentHashMap内部使用段(Segment)来表示不同的部分,每个段就是一个小的HashTable,有自己的锁,只要多个修改操作,发生在不同的段上,就可以并发进行。

把一个整体分成16个段,最高支持16个线程的并发修改操作,在多线程中减小锁的粒度,从而降低锁竞争的一种方案,共享变量使用了volatile关键字声明,目的是第一时间获取修改的内容。

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class UseConcurrentMap {
    public static void main(String[] args) {
        ConcurrentHashMap<String,Object> chm=new ConcurrentHashMap<String, Object>();
        chm.put("k1", "v1");
        chm.put("k1", "v7777");//覆盖
        chm.put("k2", "v2");
        chm.put("k3", "v3");
        chm.putIfAbsent("k4", "vvvv"); //存在 就不放入了
        chm.putIfAbsent("k4", "555");
        System.out.println(chm.get("k2"));
        System.out.println(chm.size());
        for (Map.Entry<String,Object> me:chm.entrySet()){
            System.out.println("key:" + me.getKey() + ",value:" + me.getValue());
        }
    }
}

  

import java.util.concurrent.TimeUnit;

public class TimeUinitTest {
    private TimeUnit timeUnit = TimeUnit.DAYS;
    public static void main(String[] TimeUinitTest) {
        TimeUinitTest tut = new TimeUinitTest();
        tut.outInfo();
    }
    public void outInfo() {
        System.out.println(timeUnit.name());
        System.out.println(timeUnit.toDays(1));
        System.out.println(timeUnit.toHours(1));
        System.out.println(timeUnit.toMinutes(1));
        System.out.println(timeUnit.toSeconds(1));
        System.out.println(timeUnit.toMillis(1));
        System.out.println(timeUnit.toMicros(1));
        System.out.println(timeUnit.toNanos(1));
        System.out.println((timeUnit.convert(1, TimeUnit.DAYS)) + timeUnit.name());
        System.out.println((timeUnit.convert(24, TimeUnit.HOURS)) + timeUnit.name());
        System.out.println((timeUnit.convert(1440, TimeUnit.MINUTES)) + timeUnit.name());
        System.out.println("-------------------");
    }
}

  

public class Task implements Comparable<Task>{
    private int id ;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public int compareTo(Task task){
        return this.id>task.id?1:(this.id<task.id?-1:0);
    }
    public String toString(){
        return this.id + "," + this.name;
    }
}

  

Copy-On-Write容器:程序设计中的优化策略

两种:CopyOneWriteArrayList和CopyOnWriteArraySet

Copy-On-Write容器为写时复制的容器,当往一个容器添加元素的时候,不直接往当前容器添加,而是将当前容器就行Copy,复制出一个新的容器,然后新的容器中添加元素,添加完元素之后,在将原容器的引用指向新容器。

可以对CopyOneWrite容器进行并发的读,不需要枷锁,当前容器不会添加任何元素,所以CopyOnWrite也是一种读写分离的思想,读和写在不同的容器中

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

public class UseCopyOnWrite {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> cwal=new CopyOnWriteArrayList<String>();
        CopyOnWriteArraySet<String> cwas = new CopyOnWriteArraySet<String>();
    }
}

  并发Queue:

 

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;

  

public class UseQueue {
    public static void main(String[] args) throws Exception {

        //高性能无阻塞无界队列:ConcurrentLinkedQueue  offer和add是没有区别的

         ConcurrentLinkedQueue<String> q = new ConcurrentLinkedQueue<String>();
         q.offer("a");
         q.offer("b");
         q.offer("c");
         q.offer("d");
         q.add("e");

         System.out.println(q.poll());	//a 从头部取出元素,并从队列里删除
         System.out.println(q.size());	//4
         System.out.println(q.peek());	//b
         System.out.println(q.size());	//4



         ArrayBlockingQueue<String> array = new ArrayBlockingQueue<String>(5);
         array.put("a");
         array.put("b");
         array.add("c");
         array.add("d");
         array.add("e");
         array.add("f");
         //System.out.println(array.offer("a", 3, TimeUnit.SECONDS));




         //阻塞队列
         LinkedBlockingQueue<String> q = new LinkedBlockingQueue<String>();
         q.offer("a");
         q.offer("b");
         q.offer("c");
         q.offer("d");
         q.offer("e");
         q.add("f");
         //System.out.println(q.size());

         //		for (Iterator iterator = q.iterator(); iterator.hasNext();) {
         //			String string = (String) iterator.next();
         //			System.out.println(string);
         //		}

         List<String> list = new ArrayList<String>();
         System.out.println(q.drainTo(list, 3));
         System.out.println(list.size());
         for (String string : list) {
         System.out.println(string);
         }



        final SynchronousQueue<String> q = new SynchronousQueue<String>();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(q.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                q.add("asdasd");
            }
        });
        t2.start();
    }
}

  BlockingQueue接口:(下面的全是阻塞的)

 

import java.util.concurrent.PriorityBlockingQueue;

public class UsePriorityBlockingQueue {
    public static void main(String[] args) throws Exception{

        PriorityBlockingQueue<Task> q = new PriorityBlockingQueue<Task>();

        Task t1 = new Task();
        t1.setId(3);
        t1.setName("id为3");
        Task t2 = new Task();
        t2.setId(4);
        t2.setName("id为4");
        Task t3 = new Task();
        t3.setId(1);
        t3.setName("id为1");

        //return this.id > task.id ? 1 : 0;
        q.add(t1);	//3
        q.add(t2);	//4
        q.add(t3);  //1

        // 1 3 4
        System.out.println("容器:" + q);
        System.out.println(q.take().getId());
        System.out.println("容器:" + q);
		System.out.println(q.take().getId());
		System.out.println(q.take().getId());
    }
}

  

 //没有缓存的队列,生产者产生的数据会被消费者直接消费掉
        final SynchronousQueue<String> q = new SynchronousQueue<String>();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("进入到t1线程中,阻塞等待获取元素");
                    System.out.println("消费"+q.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        TimeUnit.SECONDS.sleep(2);
        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                q.add("asdasd");
            }
        });
        t2.start();
    }

  

import java.util.concurrent.DelayQueue;

public class WangBa implements Runnable{
private DelayQueue<Wangmin> queue=new DelayQueue<Wangmin>();
    public boolean yinye =true;

    public void shangji(String name,String id,int money){
        Wangmin man = new Wangmin(name, id, 1000 * money + System.currentTimeMillis());
        System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"交钱"+money+"块,开始上机...");
        this.queue.add(man);
    }
    public void xiaji(Wangmin man){
        System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"时间到下机...");
    }

    @Override
    public void run() {
        while(yinye){
            try {
                Wangmin man = queue.take();
                xiaji(man);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String args[]){
        try{
            System.out.println("网吧开始营业");
            WangBa siyu = new WangBa();
            Thread shangwang = new Thread(siyu);
            shangwang.start();

            siyu.shangji("路人甲", "123", 1);
            siyu.shangji("路人乙", "234", 10);
            siyu.shangji("路人丙", "345", 5);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

  

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class Wangmin implements Delayed {
    private String name;
    //身份证
    private String id;
    //截止时间
    private long endTime;
    //定义时间工具类
    private TimeUnit timeUnit = TimeUnit.SECONDS;

    public Wangmin(String name,String id,long endTime){
        this.name=name;
        this.id=id;
        this.endTime = endTime;
    }

    public String getName(){
        return this.name;
    }

    public String getId(){
        return this.id;
    }

    /**
     * 用来判断是否到了截止时间
     */
    @Override
    public long getDelay(TimeUnit unit) {
        //return unit.convert(endTime, TimeUnit.MILLISECONDS) - unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        return endTime - System.currentTimeMillis();
    }

    /**
     * 相互批较排序用
     */
    @Override
    public int compareTo(Delayed delayed) {
        Wangmin w = (Wangmin)delayed;
        return this.getDelay(this.timeUnit) - w.getDelay(this.timeUnit) > 0 ? 1:0;
    }
}

  AQS锁:

 

 

 

Thread A = new Thread(new Runnable() {
			
			@Override
			public void run() {
				int sum = 0;
				for(int i =0; i < 10; i ++){
					sum += i;
				}
				try {
					Thread.sleep(4000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				LockSupport.park();	//后执行
				System.err.println("sum: " + sum);
			}
		});
		
		A.start();
		
		Thread.sleep(1000);
		
		LockSupport.unpark(A);	//先执行

  

posted @ 2019-05-10 12:31  石shi  阅读(324)  评论(0编辑  收藏  举报