• 多线程学习(十四)


    死锁



    死锁:等待形成一个循环

    操作系统中经典问题: 哲学进餐问题

    package Philosopher;
    
    public class Chopstick {
    	private boolean taken = false;
    
    	public synchronized void take() {
    		while (taken) {
    			try {
    				wait();
    			} catch (InterruptedException e) {
    				System.out.println("take interrupt");
    			}
    		}
    		taken = true;
    	}
    
    	public synchronized void off() {
    		taken = false;
    		notifyAll();
    	}
    }
    
    
    package Philosopher;
    
    import java.util.concurrent.TimeUnit;
    
    public class Philosopher implements Runnable {
    	private final int id;
    	private Chopstick left;
    	private Chopstick right;
    
    	public Philosopher(int id, Chopstick left, Chopstick right) {
    		super();
    		this.id = id;
    		this.left = left;
    		this.right = right;
    	}
    
    	public void thinking() {
    		try {
    			TimeUnit.MILLISECONDS.sleep(30);
    		} catch (InterruptedException e) {
    			System.out.println("philosopher pause interrupt");
    		}
    	}
    
    	public void eating() {
    		try {
    			TimeUnit.MILLISECONDS.sleep(60);
    		} catch (InterruptedException e) {
    			System.out.println("philosopher pause interrupt");
    		}
    	}
    
    	@Override
    	public void run() {
    		while (!Thread.interrupted()) {
    			System.out.println(this + " thinking");
    			thinking();
    			System.out.println(this + " take left  chopstick");
    			left.take();
    			System.out.println(this + " take right chopstick");
    			right.take();
    			System.out.println(this + " begin eating");
    			eating();
    			System.out.println(this + " off left");
    			left.off();
    			System.out.println(this + " off right");
    			right.off();
    		}
    	}
    
    	@Override
    	public String toString() {
    		return "Philosopher [id=" + id + "]";
    	}
    
    }
    
    package Philosopher;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class Main {
    	private static int nums = 3;
    
    	public static void main(String[] args) throws Exception {
    		ExecutorService exec = Executors.newCachedThreadPool();
    		Chopstick[] chops = new Chopstick[nums];// 3根筷子
    		for (int i = 0; i < chops.length; i++) {
    			chops[i] = new Chopstick();// 初始化筷子
    		}
    		Philosopher[] phils = new Philosopher[nums];
    		for (int i = 0; i < chops.length; i++) {
    			phils[i] = new Philosopher(i, chops[i], chops[(i + 1) % nums]); // 初始化哲学家
    		}
    		for (int i = 0; i < nums; i++) {
    			exec.execute(phils[i]);
    		}
    		TimeUnit.MILLISECONDS.sleep(300);
    //		exec.shutdownNow();
    	}
    }
    

    根据输出可以看出她 死锁了,原因分析 3 个 哲学家都拿到了左边的筷子 现在都想去拿右边的筷子 现在已经没有筷子可拿了 ,他们都持有自己 筷子放弃。就形成了死锁。

    要修正死锁的问题,那么首先必须明白死锁的发生的必要条件:

    1. 互斥条件,任务使用的资源至少有一个是不能被共享的。这里一根筷子一次只能被一个哲学家使用
    2. 至少有一个任务正持有资源正在等待获取一个别的任务正持有的资源。这里是 哲学家持有一个筷子正在等待别的哲学家的持有的筷子
    3. 资源不能被任务抢占,任务必须把资源释放当做普通时间。这里是 哲学家都很有礼貌没有去抢夺别的哲学家拥有的筷子
    4. 必须有循环等待。一个任务正在等待其他任务持有的资源,后者又在等待另一个任务持有的资源。以此类推下去....
      因为发生死锁必须满足以上四个条件,那么避免死锁只需要破坏其中的一个条件即可。
      程序中最容易破坏的是第四个条件:
      本例中 所有的哲学家都是先拿 左边的 筷子 再拿 右边的 筷子,现在只要让 最后 或者 (其中任意一个哲学家) 先拿 右边的筷子 再拿左边的 筷子皆可: 这里示范让最后一个哲学先拿右边的筷子
    package Philosopher;
    
    public class Chopstick {
    	private boolean taken = false;
    
    	public synchronized void take() throws InterruptedException {
    		while (taken) {
    			wait();
    		}
    		taken = true;
    	}
    
    	public synchronized void off() {
    		taken = false;
    		notifyAll();
    	}
    }
    
    package Philosopher;
    
    import java.util.concurrent.TimeUnit;
    
    public class Philosopher implements Runnable {
    	private final int id;
    	private Chopstick left;
    	private Chopstick right;
    
    	public Philosopher(int id, Chopstick left, Chopstick right) {
    		super();
    		this.id = id;
    		this.left = left;
    		this.right = right;
    	}
    
    	public void thinking() throws InterruptedException {
    			TimeUnit.MILLISECONDS.sleep(100);
    		
    	}
    
    	public void eating() throws InterruptedException {
    			TimeUnit.MILLISECONDS.sleep(100);
    		
    	}
    
    	@Override
    	public void run() {
    		try {
    			while (!Thread.interrupted()) {
    				System.out.println(this + " thinking");
    				thinking();
    				System.out.println(this + " take left  chopstick");
    				left.take();
    				System.out.println(this + " take right chopstick");
    				right.take();
    				System.out.println(this + " begin eating");
    				eating();
    				System.out.println(this + " off left");
    				left.off();
    				System.out.println(this + " off right");
    				right.off();
    			}
    		} catch (InterruptedException e) {
    			System.out.println("philosopher interrupt");
    		}
    	}
    
    	@Override
    	public String toString() {
    		return "Philosopher [id=" + id + "]";
    	}
    
    }
    
    package Philosopher;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 破坏循环等待
     * 
     * @author joe
     *
     */
    public class Main2 {
    	private static int nums = 3;
    
    	public static void main(String[] args) throws Exception {
    		ExecutorService exec = Executors.newCachedThreadPool();
    		Chopstick[] chops = new Chopstick[nums];// 3根筷子
    		for (int i = 0; i < chops.length; i++) {
    			chops[i] = new Chopstick();// 初始化筷子
    		}
    		Philosopher[] phils = new Philosopher[nums];
    		for (int i = 0; i < nums; i++) {
    			if (i < nums - 1)
    				phils[i] = new Philosopher(i, chops[i], chops[(i + 1) % nums]); // 初始化哲学家
    			else
    				phils[i] = new Philosopher(i, chops[(i + 1) % nums], chops[i]);
    		}
    		for (int i = 0; i < nums; i++) {
    			exec.execute(phils[i]);
    		}
    		TimeUnit.MILLISECONDS.sleep(300);
    		System.out.println("to interrput all threads");
    		exec.shutdownNow();
    	}
    }
    

    这里有个坑就是 如果按照 上面死锁的 chopstick 和philosopher的写法的话 程序是无法终止的意思是那个shutdonwnnow 无法终止这个程序。(原因以前说过 这里是因为在其他地方抛出了InterruptedException 会导致jvm 丢失当前线程的状态位 所有 Thread.interrupted()函数一直返回 false,以后要注意抛出InterrputedException 和 中断状态检查的 !!!)

    新类库中的构件

    java SE5 中的 juc引入了大量设计来解决并发问题,学习他们将哟有助于编写更加简单而健壮的并发程序。
    举例具有代表性的组件:

    CountDownLatch

    package component;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    
    public class TaskPortion implements Runnable {
    	private static int start;
    	private final int id = start++;
    	private CountDownLatch countDown;
    
    	public TaskPortion(CountDownLatch countDown) {
    		super();
    		this.countDown = countDown;
    	}
    
    	@Override
    	public void run() {
    		try {
    			pause();
    			countDown.countDown();
    		} catch (InterruptedException e) {
    			System.out.println(this + " interrupt");
    		}
    	}
    
    	@Override
    	public String toString() {
    		return "TaskPortion [id=" + id + "]";
    	}
    
    	public synchronized void pause() throws InterruptedException {
    		TimeUnit.MILLISECONDS.sleep(100);
    	}
    }
    
    
    package component;
    
    import java.util.concurrent.CountDownLatch;
    
    public class WaitingTask implements Runnable {
    	private static int start;
    	private final int id = start++;
    	private CountDownLatch countDown;
    
    	public WaitingTask(CountDownLatch countDown) {
    		super();
    		this.countDown = countDown;
    	}
    
    	@Override
    	public void run() {
    		try {
    			countDown.await();
    			System.out.println(this + " pass here");
    		} catch (InterruptedException e) {
    			System.out.println(this + " interrupt");
    		}
    
    	}
    
    	@Override
    	public String toString() {
    		return "WaitingTask [id=" + id + "]";
    	}
    
    }
    
    package component;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class CountDownDemo {
    	private static int num = 10;
    
    	public static void main(String[] args) throws InterruptedException {
    		ExecutorService exec = Executors.newCachedThreadPool();
    		CountDownLatch countDown = new CountDownLatch(num);
    		for (int i = 0; i < num; i++) {
    			exec.execute(new TaskPortion(countDown));
    		}
    		for (int i = 0; i < 3; i++) {
    			exec.execute(new WaitingTask(countDown));
    
    		}
    		TimeUnit.MILLISECONDS.sleep(3000);
    		exec.shutdownNow();
    	}
    }
    

    解释一下 在countDown没有减到0之前 waitingTask都将阻塞等待。当TaskPortion 执行将CountDown减到0时候 WaitingTask才会执行。

    下面是 赛马游戏 的仿真:

    package Horse;
    
    import java.util.Random;
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class Horse implements Runnable {
    	private static int count = 0;
    	private final int id = ++count;
    	private static CyclicBarrier cyclicBarrier;
    	private int strides = 0;
    	private static Random random = new Random();
    
    	public Horse(CyclicBarrier cyclicBarrier) {
    		super();
    		this.cyclicBarrier = cyclicBarrier;
    	}
    
    	public synchronized int getStrides() {
    		return strides;
    	}
    
    	@Override
    	public void run() {
    		try {
    			while (!Thread.interrupted()) {
    				/**
    				 * 这里的加锁主要是main函数中有调用getStrides()函数 会导致多个线程对strides这个变量的 共享 所以要加锁
    				 * 同时random.nextInt 是线程安全的
    				 */
    				synchronized (this) {
    					strides += random.nextInt(3);
    				}
    				cyclicBarrier.await();
    			}
    		} catch (InterruptedException ie) {
    			System.out.println(this + " interrupt");
    		} catch (BrokenBarrierException bbe) {
    			System.out.println(this + " broken");
    		}
    	}
    
    	@Override
    	public String toString() {
    		return "Horse [id=" + id + "]";
    	}
    
    	public String tracks() {
    		StringBuilder sb = new StringBuilder();
    		for (int i = 0; i < getStrides(); i++) {
    			sb.append("*");
    		}
    		sb.append(id);
    		return sb.toString();
    	}
    }
    
    package Horse;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class Race {
    	private final static int FINISH_LINE = 75;
    	private static CyclicBarrier cyclic;
    	private static ExecutorService exec = Executors.newCachedThreadPool();
    	private static List<Horse> horseList = new ArrayList<Horse>();
    
    	public static void main(String[] args) {
    
    		cyclic = new CyclicBarrier(5, new Runnable() {
    
    			@Override
    			public void run() {
    				StringBuilder sb = new StringBuilder();
    				for (int i = 0; i < FINISH_LINE; i++) {
    					sb.append("=");
    				}
    				System.out.println(sb.toString());
    				for (Horse h : horseList) {
    					System.out.println(h.tracks());
    				}
    				
    				for (Horse h : horseList) {
    					if (h.getStrides() >= FINISH_LINE) {
    						System.out.println(h + " win");
    						exec.shutdownNow();
    						return; // 不执行下面的操作了
    					}
    				}
    				try {
    					TimeUnit.MILLISECONDS.sleep(200);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    
    			}
    		});
    		for (int i = 0; i < 5; i++) {
    			Horse horse = new Horse(cyclic);
    			horseList.add(horse);
    			exec.execute(horse); 
    			/**
    			 * 这里不用担心 我的horseList 还没有创建好,上面的cyclic 会不会空指针或者 horseList不安全
    			 * 不会的 只用当5个线程都执行完到“栅栏” 的时候 cyclic中的Runable方法才会执行,也就是说只用当5个horse都execute之后cyclic中的
    			 * runable才有机会执行。
    			 */
    		}
    	}
    }
    

    过程中:

    结果:

    这个程序还有点问题:就是无法识别 同时过线 两个 谁是第一谁是第二

    DelayQueue

    package DelayQueue;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Delayed;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class DelayTask implements Runnable, Delayed {
    	private static int count = 0;
    	private final int id = ++count;
    	private final int delta;
    	private final long trigger;
    	protected static List<DelayTask> sequence = new ArrayList<DelayTask>();
    
    	public DelayTask(int delayInMilliseconds) {
    		this.delta = delayInMilliseconds;
    		this.trigger = System.nanoTime() + TimeUnit.NANOSECONDS.convert(delta, TimeUnit.MILLISECONDS);
    		sequence.add(this);
    	}
    
    	@Override
    	public int compareTo(Delayed that) {
    		DelayTask delayTask = (DelayTask) that;
    		if (trigger < delayTask.trigger)
    			return -1;
    		if (trigger > delayTask.trigger)
    			return 1;
    		return 0;
    	}
    
    	@Override
    	public long getDelay(TimeUnit unit) {
    		return unit.convert(trigger - System.nanoTime(), TimeUnit.NANOSECONDS);
    	}
    
    	@Override
    	public void run() {
    		System.out.println(this);
    	}
    
    	@Override
    	public String toString() {
    		return "DelayTask [id=" + id + "], [delta=" + delta + "]";
    	}
    
    	public static class EndSentinel extends DelayTask {
    		private ExecutorService exec;
    
    		public EndSentinel(int delayInMilliseconds, ExecutorService exec) {
    			super(delayInMilliseconds);
    			this.exec = exec;
    		}
    
    		@Override
    		public void run() {
    			System.out.println("begin endsentinel");
    			for (DelayTask dt : sequence) {
    				System.out.println(dt);
    			}
    			System.out.println("begin shutdownNow");
    			exec.shutdownNow();
    		}
    
    	}
    
    }
    
    package DelayQueue;
    
    import java.util.Random;
    import java.util.concurrent.DelayQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class DelayQueueConsumer implements Runnable {
    	private DelayQueue<DelayTask> delayedQueue;
    
    	public DelayQueueConsumer(DelayQueue<DelayTask> delayedQueue) {
    		super();
    		this.delayedQueue = delayedQueue;
    	}
    
    	@Override
    	public void run() {
    		try {
    			while (!Thread.interrupted()) {
    				delayedQueue.take().run();
    			}
    		} catch (InterruptedException ie) {
    			System.out.println("consumer interrup");
    		}
    	}
    
    	public static void main(String[] args) {
    		Random random = new Random(5000);
    		ExecutorService exec = Executors.newCachedThreadPool();
    		DelayQueue<DelayTask> queue = new DelayQueue<>();
    		for (int i = 0; i < 20; i++) {
    			queue.put(new DelayTask(random.nextInt(5000)));
    		}
    		queue.add(new DelayTask.EndSentinel(5000, exec));
    		exec.execute(new DelayQueueConsumer(queue));
    	}
    }
    
    DelayTask [id=11], [delta=131]
    DelayTask [id=16], [delta=157]
    DelayTask [id=15], [delta=196]
    DelayTask [id=1], [delta=534]
    DelayTask [id=6], [delta=572]
    DelayTask [id=10], [delta=609]
    DelayTask [id=2], [delta=668]
    DelayTask [id=20], [delta=952]
    DelayTask [id=14], [delta=1078]
    DelayTask [id=7], [delta=1092]
    DelayTask [id=8], [delta=1420]
    DelayTask [id=12], [delta=2519]
    DelayTask [id=5], [delta=2686]
    DelayTask [id=3], [delta=2766]
    DelayTask [id=9], [delta=2884]
    DelayTask [id=19], [delta=3156]
    DelayTask [id=4], [delta=3198]
    DelayTask [id=17], [delta=3445]
    DelayTask [id=13], [delta=4123]
    DelayTask [id=18], [delta=4621]
    begin endsentinel
    DelayTask [id=1], [delta=534]
    DelayTask [id=2], [delta=668]
    DelayTask [id=3], [delta=2766]
    DelayTask [id=4], [delta=3198]
    DelayTask [id=5], [delta=2686]
    DelayTask [id=6], [delta=572]
    DelayTask [id=7], [delta=1092]
    DelayTask [id=8], [delta=1420]
    DelayTask [id=9], [delta=2884]
    DelayTask [id=10], [delta=609]
    DelayTask [id=11], [delta=131]
    DelayTask [id=12], [delta=2519]
    DelayTask [id=13], [delta=4123]
    DelayTask [id=14], [delta=1078]
    DelayTask [id=15], [delta=196]
    DelayTask [id=16], [delta=157]
    DelayTask [id=17], [delta=3445]
    DelayTask [id=18], [delta=4621]
    DelayTask [id=19], [delta=3156]
    DelayTask [id=20], [delta=952]
    DelayTask [id=21], [delta=5000]
    begin shutdownNow
    

    可以从输出看出,其实DelayQueue 会首先执行delay时间最小的任务 到它该发生的时间的点去执行。
    需要注意的是:1.getDelay() 返回的是纳秒数。 2.compareTo函数 大于时候必须返回 整数(也就是说 小于的时候必须返回负数 其实也就是说必须按照 从小到大的 顺序排列)
    其实这个就相当于一个 根据发生发生时间的优先级队列。

    PriorityBlockingQueue

    package priorityQueue;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class PriorityTask implements Runnable, Comparable<PriorityTask> {
    	private static int count = 0;
    	private final int id = ++count;
    	private final int priority;
    
    	protected static List<PriorityTask> priorityList = new ArrayList<>();
    
    	public PriorityTask(int priority) {
    		super();
    		this.priority = priority;
    		priorityList.add(this);
    	}
    
    	@Override
    	public void run() {
    		System.out.println(this);
    		try {
    			TimeUnit.MILLISECONDS.sleep(200);
    		} catch (InterruptedException e) {
    			System.out.println("PriorityQueue interrupt");
    		}
    	}
    
    	@Override
    	public int compareTo(PriorityTask that) {
    		return priority > that.priority ? -1 : (priority < that.priority ? 1 : 0);
    	}
    
    	@Override
    	public String toString() {
    		return "PriorityTask [id=" + id + "],[ priority=" + priority + "]";
    	}
    
    	public static class End extends PriorityTask {
    		private ExecutorService exec;
    
    		public End(int priority, ExecutorService exec) {
    			super(-1);// 设置最低的优先级 让其最后执行
    			this.exec = exec;
    		}
    
    		@Override
    		public void run() {
    			System.out.println("begin end:");
    			for (PriorityTask pt : priorityList) {
    				System.out.println(pt);
    			}
    			System.out.println("shutdownNow");
    			exec.shutdownNow();
    		}
    
    	}
    }
    
    package priorityQueue;
    
    import java.util.Queue;
    import java.util.concurrent.ExecutorService;
    
    public class PriorityQueueProducer implements Runnable {
    	private  Queue<PriorityTask> priorityQueue;
    	private ExecutorService exec;// 用于 Priority.End 
    
    	public PriorityQueueProducer(Queue<PriorityTask> priorityQueue, ExecutorService exec) {
    		super();
    		this.priorityQueue = priorityQueue;
    		this.exec = exec;
    	}
    
    
    	@Override
    	public void run() {
    		for (int i = 0; i < 5; i++) {
    			priorityQueue.add(new PriorityTask(5));
    		}
    		for (int i = 0; i < 5; i++) {
    			priorityQueue.add(new PriorityTask(10));
    		}
    		for (int i = 0; i < 5; i++) {
    			priorityQueue.add(new PriorityTask(20));
    		}
    		priorityQueue.add(new PriorityTask.End(-1, exec));
    	}
    
    }
    
    package priorityQueue;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.PriorityBlockingQueue;
    
    public class PriorityQueueConsumer implements Runnable {
    	private static PriorityBlockingQueue<PriorityTask> pq;
    
    	@Override
    	public void run() {
    		try {
    			while (!Thread.interrupted()) {
    				PriorityTask pt = pq.take();
    				pt.run();
    			}
    		} catch (InterruptedException e) {
    			System.out.println("consumer interrupt");
    		}
    	}
    
    	public static void main(String[] args) {
    		pq=new PriorityBlockingQueue<>();
    		ExecutorService exec=Executors.newCachedThreadPool();
    		exec.execute(new PriorityQueueProducer(pq, exec));
    		exec.execute(new PriorityQueueConsumer());
    	}
    }
    
    PriorityTask [id=6],[ priority=10]
    PriorityTask [id=11],[ priority=20]
    PriorityTask [id=12],[ priority=20]
    PriorityTask [id=13],[ priority=20]
    PriorityTask [id=14],[ priority=20]
    PriorityTask [id=15],[ priority=20]
    PriorityTask [id=9],[ priority=10]
    PriorityTask [id=8],[ priority=10]
    PriorityTask [id=10],[ priority=10]
    PriorityTask [id=7],[ priority=10]
    PriorityTask [id=1],[ priority=5]
    PriorityTask [id=3],[ priority=5]
    PriorityTask [id=2],[ priority=5]
    PriorityTask [id=5],[ priority=5]
    PriorityTask [id=4],[ priority=5]
    begin end:
    PriorityTask [id=1],[ priority=5]
    PriorityTask [id=2],[ priority=5]
    PriorityTask [id=3],[ priority=5]
    PriorityTask [id=4],[ priority=5]
    PriorityTask [id=5],[ priority=5]
    PriorityTask [id=6],[ priority=10]
    PriorityTask [id=7],[ priority=10]
    PriorityTask [id=8],[ priority=10]
    PriorityTask [id=9],[ priority=10]
    PriorityTask [id=10],[ priority=10]
    PriorityTask [id=11],[ priority=20]
    PriorityTask [id=12],[ priority=20]
    PriorityTask [id=13],[ priority=20]
    PriorityTask [id=14],[ priority=20]
    PriorityTask [id=15],[ priority=20]
    PriorityTask [id=16],[ priority=-1]
    shutdownNow
    

    这个也不是绝对的 优先级最大的最先执行,只是在执行的时候,睡的优先级最大谁就执行:

    PriorityTask [id=6],[ priority=10]
    PriorityTask [id=11],[ priority=20]
    PriorityTask [id=12],[ priority=20]
    PriorityTask [id=13],[ priority=20]
    PriorityTask [id=14],[ priority=20]
    PriorityTask [id=15],[ priority=20]
    PriorityTask [id=9],[ priority=10]
    PriorityTask [id=8],[ priority=10]
    PriorityTask [id=10],[ priority=10]
    PriorityTask [id=7],[ priority=10]
    PriorityTask [id=1],[ priority=5]
    PriorityTask [id=3],[ priority=5]
    PriorityTask [id=2],[ priority=5]
    PriorityTask [id=5],[ priority=5]
    PriorityTask [id=4],[ priority=5]
    begin end:
    PriorityTask [id=1],[ priority=5]
    PriorityTask [id=2],[ priority=5]
    PriorityTask [id=3],[ priority=5]
    PriorityTask [id=4],[ priority=5]
    PriorityTask [id=5],[ priority=5]
    PriorityTask [id=6],[ priority=10]
    PriorityTask [id=7],[ priority=10]
    PriorityTask [id=8],[ priority=10]
    PriorityTask [id=9],[ priority=10]
    PriorityTask [id=10],[ priority=10]
    PriorityTask [id=11],[ priority=20]
    PriorityTask [id=12],[ priority=20]
    PriorityTask [id=13],[ priority=20]
    PriorityTask [id=14],[ priority=20]
    PriorityTask [id=15],[ priority=20]
    PriorityTask [id=16],[ priority=-1]
    shutdownNow
    

    ** ScheduledExecutor **

    相当于定时任务
    schedule 在延迟的一段时间后执行一次任务
    scheduleAtFixRate 每隔规则的时候 重复执行任务

    package GreenHouse;
    
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Collections;
    import java.util.List;
    import java.util.Random;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class GreenHose {
    	private volatile boolean light = false;
    	private volatile boolean water = false;
    	private String thermostat = "Day";
    
    	public synchronized String getThermostat() {
    		return thermostat;
    	}
    
    	public synchronized void setThermostat(String thermostat) {
    		this.thermostat = thermostat;
    	}
    
    	ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(10);
    
    	public void schedule(Runnable event, long delay) {
    		scheduler.schedule(event, delay, TimeUnit.MILLISECONDS);
    	}
    
    	public void repeat(Runnable event, long init, long period) {
    		scheduler.scheduleAtFixedRate(event, init, period, TimeUnit.MILLISECONDS);
    	}
    
    	class LightOn implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("light on");
    			light = true;
    		}
    
    	}
    
    	class LightOff implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("light off");
    			light = false;
    		}
    
    	}
    
    	class WaterOn implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("water on");
    			water = true;
    		}
    
    	}
    
    	class WaterOff implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("water off");
    			water = false;
    		}
    
    	}
    
    	class Night implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("Night...");
    			setThermostat("Night");
    		}
    
    	}
    
    	class Day implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("Day");
    			setThermostat("Day");
    		}
    
    	}
    
    	class Bell implements Runnable {
    
    		@Override
    		public void run() {
    			System.out.println("bell ");
    		}
    	}
    
    	class Terminate implements Runnable {
    		@Override
    		public void run() {
    			System.out.println("Terminate...");
    			scheduler.shutdownNow();
    			new Thread() {
    				@Override
    				public void run() {
    					// 输出现在的 系统的状态
    					for(DataPoint dp:data){
    						System.out.println(dp);
    					}
    				}
    			}.start();
    		}
    	}
    
    	static class DataPoint {
    		private final Calendar time;
    		private final float temperature;
    		private final float humiduty;
    
    		@Override
    		public synchronized String toString() {
    			/**
    			 * 这里加锁 是因为要访问共享的数据 time、temperature 等
    			 */
    			return "DatePoint [time=" + time.getTime() + ", temperature=" + temperature + ", humiduty=" + humiduty + "]";
    		}
    
    		public DataPoint(Calendar time, float temperature, float humiduty) {
    			super();
    			this.time = time;
    			this.temperature = temperature;
    			this.humiduty = humiduty;
    		}
    	}
    
    	private Calendar lastTime = Calendar.getInstance();
    	{
    		lastTime.set(Calendar.MINUTE, 30);
    		lastTime.set(Calendar.SECOND, 0);
    	}
    	private float lastTemp = 65.0f;
    	private int tempDirection = +1;
    	private float lastHumidity = 50.0f;
    	private int humidityDescrtion = +1;
    	private Random random = new Random();
    	List<DataPoint> data = Collections.synchronizedList(new ArrayList<>());
    
    	class CollectData implements Runnable {
    
    		@Override
    		public void run() {
    			synchronized (GreenHose.this) {
    				// 这里是收集 数据的 代码
    				lastTime.set(Calendar.MINUTE, lastTime.get(Calendar.MINUTE) + 30);
    				if (random.nextInt(5) == 4) {
    					tempDirection = -tempDirection;
    				}
    				lastTemp = lastTemp + tempDirection * (1.0f + random.nextFloat());
    				if (random.nextInt(5) == 4)
    					humidityDescrtion = -humidityDescrtion;
    				lastHumidity = lastHumidity + humidityDescrtion * random.nextFloat();
    				data.add(new DataPoint((Calendar) lastTime.clone(), lastTemp, lastHumidity));
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		GreenHose gh = new GreenHose();
    		gh.schedule(gh.new Terminate(), 5000);
    		gh.repeat(gh.new Bell(), 0, 1000);
    		gh.repeat(gh.new Night(), 0, 2000);
    		gh.repeat(gh.new LightOn(), 0, 200);
    		gh.repeat(gh.new LightOff(), 0, 400);
    		gh.repeat(gh.new WaterOn(), 0, 600);
    		gh.repeat(gh.new WaterOff(), 0, 800);
    		gh.repeat(gh.new Day(), 0, 1400);
    		gh.repeat(gh.new CollectData(), 0, 500);
    	}
    }
    

    Semaphore

    信号量的使用

    package Semaphore;
    
    import java.util.List;
    import java.util.concurrent.Semaphore;
    
    public class Pool<T> {
    	private int size;
    	private List<T> pool;
    	private boolean[] flags;
    	private Semaphore available;
    
    	public Pool(Class<T> clazz, int size) {
    		super();
    		this.size = size;
    		for (int i = 0; i < size; i++) {
    			try {
    				T t = (T) clazz.newInstance();
    				pool.add(t);
    			} catch (InstantiationException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} catch (IllegalAccessException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		flags = new boolean[size];
    		available = new Semaphore(size, true);
    	}
    
    	public T checkout() {
    		try {
    			available.acquire(); // 如果没有将会阻塞调用
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return getItem();
    	}
    
    	private synchronized T getItem() {
    		for (int i = 0; i < size; i++) {
    			if (!flags[i]) {
    				flags[i] = true;
    				return pool.get(i);
    			}
    		}
    		return null;
    	}
    
    	public void checkIn(T t) {
    		if (returnTtem(t))
    			available.release();
    	}
    
    	private synchronized boolean returnTtem(T t) {
    		int index = pool.indexOf(t);
    		if (index < 0) {
    			throw new IllegalArgumentException("参数不正确");
    		}
    		if (flags[index]) {
    			flags[index] = false;
    			return true;
    		}
    		return false;
    	}
    
    }
    
    package Semaphore;
    
    public class Fat {
    	private static int count = 0;
    	private final int id = ++count;
    	private volatile double d;// 这里声明 volatile的目的是 不希望编译器优化它
    
    	public Fat() {
    		for (int i = 0; i < 50000; i++) {
    			d = (Math.PI / Math.E) * Math.PI; // cost time operation
    		}
    	}
    
    	public void operation() {
    		System.out.println(this + " operation");
    	}
    
    	@Override
    	public String toString() {
    		return "Fat [id=" + id + "]";
    	}
    
    }
    
    package Semaphore;
    
    import java.util.concurrent.TimeUnit;
    
    public class CheckTask<T> implements Runnable {
    	private static int count;
    	private final int id = ++count;
    	private Pool<T> pool;
    
    	public CheckTask(Pool<T> pool) {
    		super();
    		this.pool = pool;
    	}
    
    	@Override
    	public void run() {
    		T t = pool.checkout();
    		System.out.println(this + " check out " + t);
    		try {
    			TimeUnit.MILLISECONDS.sleep(200);
    		} catch (InterruptedException e) {
    			System.out.println("check out task interrupt");
    		}
    		pool.checkIn(t);
    		System.out.println(this + " check in " + t);
    	}
    
    	@Override
    	public String toString() {
    		return "CheckTask [id=" + id + "]";
    	}
    
    }
    
    package Semaphore;
    
    import java.util.LinkedList;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;
    
    public class SemaphoreDemo {
    	private static final int SIZE = 4;
    	private static List<Fat> fatList = new LinkedList<>();
    
    	public static void main(String[] args) throws InterruptedException {
    		Pool<Fat> fatPool = new Pool<>(Fat.class, SIZE);
    		ExecutorService exec = Executors.newCachedThreadPool();
    		for (int i = 0; i < SIZE; i++) {
    			exec.execute(new CheckTask<>(fatPool));
    		}
    		System.out.println("all check task create ");
    		for (int i = 0; i < SIZE; i++) {
    			Fat fat = fatPool.checkout();
    			fat.operation();
    			System.out.println("main check out " + fat);
    			fatList.add(fat); // all fat are check out
    		}
    
    		Future<?> fu = exec.submit(new Runnable() {
    
    			@Override
    			public void run() {
    				fatPool.checkout();// this operation will block
    			}
    		});
    		TimeUnit.MILLISECONDS.sleep(200);
    		fu.cancel(true);// interrupt
    		for (Fat f : fatList) {
    			fatPool.checkIn(f);
    		}
    		System.out.println("main check in once");
    		// check in once
    		for (Fat f : fatList) {
    			fatPool.checkIn(f);
    		}
    		System.out.println("main check int twice");
    		// check in twice
    	}
    }
    
    CheckTask [id=2] check out Fat [id=2]
    CheckTask [id=4] check out Fat [id=4]
    CheckTask [id=1] check out Fat [id=1]
    all check task create 
    CheckTask [id=3] check out Fat [id=3]
    CheckTask [id=1] check in Fat [id=1]
    Fat [id=1] operation
    main check out Fat [id=1]
    CheckTask [id=4] check in Fat [id=4]
    Fat [id=2] operation
    main check out Fat [id=2]
    Fat [id=3] operation
    main check out Fat [id=3]
    CheckTask [id=2] check in Fat [id=2]
    Fat [id=4] operation
    main check out Fat [id=4]
    CheckTask [id=3] check in Fat [id=3]
    check out interrupt
    main check in once
    main check int twice
    

    Exchanger

    package Exchanger;
    
    import Semaphore.Fat;
    
    public class FatGenerator {
    	public Fat next() {
    		return new Fat();
    	}
    }
    
    package Exchanger;
    
    import java.util.List;
    import java.util.concurrent.Exchanger;
    
    import Semaphore.Fat;
    
    public class ExchangerProducer implements Runnable {
    	private Exchanger<List<Fat>> exchanger;
    	private List<Fat> holder;
    	private FatGenerator ganerator;
    
    	public ExchangerProducer(Exchanger<List<Fat>> exchanger, List<Fat> holder, FatGenerator ganerator) {
    		super();
    		this.exchanger = exchanger;
    		this.holder = holder;
    		this.ganerator = ganerator;
    	}
    
    	@Override
    	public void run() {
    		try {
    			while (!Thread.interrupted()) {
    				for (int i = 0; i < ExchangerDemo.SIZE; i++) {
    					holder.add(ganerator.next());
    				}
    				holder=exchanger.exchange(holder);
    			}
    		} catch (InterruptedException ie) {
    			System.out.println("producer interrupt");
    		}
    	}
    
    }
    
    package Exchanger;
    
    import java.util.List;
    import java.util.concurrent.Exchanger;
    
    import Semaphore.Fat;
    
    public class ExchangerConsumer implements Runnable {
    	private List<Fat> holder;
    	private Exchanger<List<Fat>> excheager;
    
    	public ExchangerConsumer(List<Fat> holder, Exchanger<List<Fat>> excheager) {
    		super();
    		this.holder = holder;
    		this.excheager = excheager;
    	}
    
    	@Override
    	public void run() {
    		try {
    			while (!Thread.interrupted()) {
    				holder = excheager.exchange(holder);
    				for (Fat f : holder) {
    					System.out.println("consume:" + f);
    					holder.remove(f);// currentModftyException
    										// copyOnwriteArrayList可以适合这个场景 
    				}
    			}
    		} catch (InterruptedException ie) {
    			System.out.println("consumer interrupt");
    		}
    		
    	}
    
    }
    
    package Exchanger;
    
    import java.util.List;
    import java.util.concurrent.CopyOnWriteArrayList;
    import java.util.concurrent.Exchanger;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    import Semaphore.Fat;
    
    public class ExchangerDemo {
    	public final static int SIZE = 5;
    
    	public static void main(String[] args) throws InterruptedException {
    		ExecutorService exec = Executors.newCachedThreadPool();
    		Exchanger<List<Fat>> xc = new Exchanger<>();
    		List<Fat> producer = new CopyOnWriteArrayList<>(), consumer = new CopyOnWriteArrayList<>();
    		FatGenerator generator = new FatGenerator();
    		exec.execute(new ExchangerProducer(xc, producer, generator));
    		exec.execute(new ExchangerConsumer(consumer, xc));
    		TimeUnit.MILLISECONDS.sleep(20);
    		exec.shutdownNow();
    	}
    }
    

    到此为止 大概的juc 中的代表性的 类都介绍完了

  • 相关阅读:
    微信小程序如何获取openid
    js经典试题之常用的方法
    js经典试题之运算符的优先级
    js如何使浏览器允许脚本异步加载
    es6从零学习(五):Module的语法
    es6从零学习(四):Class的继承
    js如何处理字符串中带有↵字符
    Zuul中聚合Swagger的坑
    阿里Sentinel支持Spring Cloud Gateway啦
    Spring Boot中的Mongodb多数据源扩展
  • 原文地址:https://www.cnblogs.com/joeCqupt/p/6848387.html
Copyright © 2020-2023  润新知