Java并发编程核心包——JUC

JUC初步

作者:李晶晶;

日期:2021年4月20日;

学习视频:2020权威_juc 与 jvm 并发编程 Java 必学_阳哥- 尚硅谷

文章目录

  • JUC初步
    • 初识Lock
      • 抢票案例
    • 生产者消费者问题
      • 使用Lock解决生产者消费者问题
    • Condition的精准唤醒
      • 轮流打印案例
    • 线程安全的集合类
      • 线程安全的List
      • 线程安全的Set
      • 线程安全的Map
    • Callable接口
      • Callable与FutureTask
    • JUC中的一些工具
      • CountDownLatch
      • CyclicBarrier
      • Semaphore
    • 读写锁
      • 使用案例
    • 阻塞队列
      • put与take
    • 线程池
      • 使用Executors创建线程池
      • ThreadPoolExecutor分析

初识Lock

抢票案例

package.初识lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 原来都是在买票的方法上加上synchronized关键字保证线程同步; 我们使用JUC中的lock来做也可以实现,而且效率更高;
 * 
 * @author 木子六日
 *
 */
public class Ticket {
	private int number = 20;
	private Lock lock = new ReentrantLock();

	public void saleTicket() {
		lock.lock();
		try {
			if (number > 0) {
				System.out.println(Thread.currentThread().getName() + "卖了一张票,剩余" + (--number));
			}
		} catch (Exception e) {
		} finally {
			lock.unlock();
		}

	}

	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		new Thread(() -> {
			for (int i = 0; i < 30; i++) {
				ticket.saleTicket();
			}
		}, "售票员甲").start();
		new Thread(() -> {
			for (int i = 0; i < 30; i++) {
				ticket.saleTicket();
			}
		}, "售票员乙").start();
		new Thread(() -> {
			for (int i = 0; i < 30; i++) {
				ticket.saleTicket();
			}
		}, "售票员丙").start();
	}
}

生产者消费者问题

使用Lock解决生产者消费者问题

package.新版生产者消费者;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用lock实现生产者消费者模型
 * 
 * @author 木子六日
 *
 */
public class Resource {
	private int count = 0;
	private ReentrantLock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();

	public void increment() {
		lock.lock();
		try {
			while (count > 0) {
				condition.await();
			}
			count++;
			System.out.println(Thread.currentThread().getName() + "\t" + count);
			condition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void decrement() {
		lock.lock();
		try {
			while (count == 0) {
				condition.await();
			}
			count--;
			System.out.println(Thread.currentThread().getName() + "\t" + count);
			condition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		Resource resource = new Resource();
		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				resource.decrement();
			}
		}, "消费者1").start();
		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				resource.decrement();
			}
		}, "消费者2").start();
		new Thread(() -> {
			for (int i = 0; i < 20; i++) {
				resource.increment();
			}
		}, "生产者1").start();
	}
}

Condition的精准唤醒

轮流打印案例

package.轮流打印;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * @author 木子六日
 */
public class ShareResource {
	private int tag = 0;
	private Lock lock = new ReentrantLock();
	private List<Condition> conditions = new ArrayList<Condition>();

	public ShareResource() {
		for (int i = 0; i < 3; i++) {
			conditions.add(lock.newCondition());
		}
	}

	public void printName(int i) {
		lock.lock();
		try {
			while (tag != i) {
				conditions.get(i).await();
			}
			tag = (i + 1) % 3;
			System.out.println(Thread.currentThread().getName());
			conditions.get(tag).signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		ShareResource resource = new ShareResource();
		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				resource.printName(0);
			}
		}, "甲").start();
		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				resource.printName(1);
			}
		}, "乙").start();
		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				resource.printName(2);
			}
		}, "丙").start();
	}
}

线程安全的集合类

线程安全的List

package.线程安全的集合类;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

public class SecureList {

	public static void main(String[] args) throws InterruptedException {
		// 线程不安全
		List<Integer> a = new ArrayList<Integer>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				a.add(0);
			}, "ArrayList").start();
		}
		// 线程安全,就是给add方法加了syn
		List<Integer> b = new Vector<Integer>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				b.add(0);
			}, "Vector").start();
		}

		// 还可以这样保证线程安全
		List<Integer> c = Collections.synchronizedList(new ArrayList<Integer>());
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				c.add(0);
			}, "synchronizedList").start();
		}

		// JUC提供的线程安全list
		List<Integer> d = new CopyOnWriteArrayList<Integer>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				d.add(0);
			}, "CopyOnWriteArrayList").start();
		}

		TimeUnit.SECONDS.sleep(5);
		System.out.println(a.size());
		System.out.println(b.size());
		System.out.println(c.size());
		System.out.println(d.size());
	}
}

线程安全的Set

package.线程安全的集合类;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;

public class SecureSet {
	public static void main(String[] args) throws InterruptedException {
		// 线程不安全
		Set<String> a = new HashSet<String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				a.add(UUID.randomUUID().toString());
			}, "HashSet").start();
		}

		// 第一种解决方案
		Set<String> b = Collections.synchronizedSet(new HashSet<String>());
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				b.add(UUID.randomUUID().toString());
			}, "synchronizedSet").start();
		}

		// JUC的解决方案
		Set<String> c = new CopyOnWriteArraySet<String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				c.add(UUID.randomUUID().toString());
			}, "CopyOnWriteArraySet").start();
		}

		TimeUnit.SECONDS.sleep(5);
		System.out.println(a.size());
		System.out.println(b.size());
		System.out.println(c.size());
	}
}

线程安全的Map

package.线程安全的集合类;

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class SecureMap {
	public static void main(String[] args) throws InterruptedException {
		// 线程不安全
		Map<String, String> a = new HashMap<String, String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				a.put(UUID.randomUUID().toString(), "0");
			}, "HashMap").start();
		}

		// Hashtable,类似Vector,就是给put方法加了syn
		Map<String, String> b = new Hashtable<String, String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				b.put(UUID.randomUUID().toString(), "0");
			}, "Hashtable").start();
		}

		// 这个是万能的
		Map<String, String> c = Collections.synchronizedMap(new HashMap<String, String>());
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				c.put(UUID.randomUUID().toString(), "0");
			}, "Hashtable").start();
		}

		// JUC的解决方案
		Map<String, String> d = new ConcurrentHashMap<String, String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				d.put(UUID.randomUUID().toString(), "0");
			}, "Hashtable").start();
		}

		TimeUnit.SECONDS.sleep(5);
		System.out.println(a.size());
		System.out.println(b.size());
		System.out.println(c.size());
		System.out.println(d.size());
	}
}

Callable接口

Callable与FutureTask

package.Callable接口;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class Mythread implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		System.out.print("icu");
		return 996;
	}
}

public class CallableDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<Integer> futureTask = new FutureTask<Integer>(new Mythread());
		futureTask.run();
		System.out.println(futureTask.get());

		// FutrueTask实现了runnable接口,所以也可以使用传统方式执行线程
		new Thread(futureTask, "A").start();
		// futureTask只会执行一次,因为里面封装了线程的状态,线程状态不是new的话就直接return了
	}
}

JUC中的一些工具

CountDownLatch

package.JUC的一些工具;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
	public static void main(String[] args) throws InterruptedException {
		CountDownLatch countDownLatch = new CountDownLatch(10);
		for (int i = 0; i < 10; i++) {
			new Thread(() -> {
				System.out.println(Thread.currentThread().getName());
				countDownLatch.countDown();
			}, i + "").start();
		}
		countDownLatch.await();
		System.out.println("main");
	}
}

CyclicBarrier

package.JUC的一些工具;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> System.out.println("main"));
		for (int i = 0; i < 10; i++) {
			new Thread(() -> {
				System.out.println(Thread.currentThread().getName());
				try {
					cyclicBarrier.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					e.printStackTrace();
				}
			}, i + "").start();
		}
	}
}

Semaphore

package.JUC的一些工具;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreDemo {

	private static int resource = 3;
	private static Random r = new Random();

	public static void main(String[] args) {
		System.out.println("共有5份资源");
		Semaphore semaphore = new Semaphore(resource);
		for (int i = 1; i <= 20; i++) {
			new Thread(() -> {
				try {
					semaphore.acquire();
					System.out.println(Thread.currentThread().getName() + "占有了资源");
					TimeUnit.SECONDS.sleep(r.nextInt(5) + 1);
					System.out.println(Thread.currentThread().getName() + "释放了资源");
				} catch (Exception e) {
				} finally {
					semaphore.release();
				}
			}, "车子" + i).start();
		}
	}
}

读写锁

使用案例

package.读写锁;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 可以读读,不能读写、写写
 * 
 * @author 木子六日
 * @date 2021年3月23日
 */
class MyCache {
	private Map<Integer, String> cache = new HashMap<Integer, String>();
	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

	public void get(Integer k) {
		try {
			readWriteLock.readLock().lock();
			System.out.println(Thread.currentThread().getName() + "开始读取数据");
			String res = cache.get(k);
			System.out.println(Thread.currentThread().getName() + "读取完成,数据是:" + res);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			readWriteLock.readLock().unlock();
		}
	}

	public void put(Integer k, String v) {
		try {
			readWriteLock.writeLock().lock();
			System.out.println(Thread.currentThread().getName() + "开始写入数据");
			cache.put(k, v);
			System.out.println(Thread.currentThread().getName() + "写入数据" + v + "成功");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			readWriteLock.writeLock().unlock();
		}
	}
}

public class ReadWriteLockDemo {
	public static void main(String[] args) {
		MyCache cache = new MyCache();
		for (int i = 1; i <= 5; i++) {
			final int k = i;
			new Thread(() -> {
				cache.put(k, UUID.randomUUID().toString());
			}, "写线程" + i).start();
		}

		for (int i = 1; i <= 5; i++) {
			final int k = i;
			new Thread(() -> {
				cache.get(k);
			}, "读线程" + i).start();
		}
	}
}

阻塞队列

put与take

package.阻塞队列;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * 原本的那些add、remove、element、offer、poll、peek队列方法照用 增加了put和take方法
 * 
 * @author 木子六日
 * @date 2021年4月20日
 */
public class BlockingQueueDemo {
	public static void main(String[] args) {
		BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(5);
		new Thread(() -> {
			while (true) {
				try {
					// 队列满了put将被阻塞
					blockingQueue.put("bread");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("生产:" + blockingQueue.size());
			}
		}, "生产者").start();

		new Thread(() -> {
			while (true) {
				// 队列空了poll将被阻塞
				blockingQueue.poll();
				System.out.println("消费:" + blockingQueue.size());
			}
		}, "消费者").start();
	}
}

线程池

使用Executors创建线程池

package.线程池;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
	public static void main(String[] args) {
		// 设置线程池大小为3
//		ExecutorService threadPool = Executors.newFixedThreadPool(3);

		// 一个线程池里就只有一个线程
//		ExecutorService threadPool = Executors.newSingleThreadExecutor();

		// 动态扩容的
		ExecutorService threadPool = Executors.newCachedThreadPool();
		for (int i = 0; i < 100; i++) {
			threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
		}
		// 需要关闭线程池
		threadPool.shutdown();
	}
}

ThreadPoolExecutor分析

package.线程池;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 分析一下ThreadPoolExecutor的七大参数
 * @author 木子六日
 * @date   2021年4月20日
 */
public class ThreadPoolExecutorAnalysis {
//这里先粘一段源码
	/*
	public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler) {
		if (corePoolSize < 0 ||
			maximumPoolSize <= 0 ||
			maximumPoolSize < corePoolSize ||
			keepAliveTime < 0)
			throw new IllegalArgumentException();
		if (workQueue == null || threadFactory == null || handler == null)
			throw new NullPointerException();
		this.acc = System.getSecurityManager() == null ?
					null :
					AccessController.getContext();
		this.corePoolSize = corePoolSize;
		this.maximumPoolSize = maximumPoolSize;
		this.workQueue = workQueue;
		this.keepAliveTime = unit.toNanos(keepAliveTime);
		this.threadFactory = threadFactory;
		this.handler = handler;
	}
	*/
	
	/*
	 	无论是Executors.newFixedThreadPool(3)
	 	还是Executors.newSingleThreadExecutor()
	 	或者Executors.newCachedThreadPool()
	 	他们都是返回的一个ThreadPoolExecutor的不同构造而已
	 	所以线程池就是ThreadPoolExecutor
	 */
	
	/*
	 	corePoolSize:
	 		常驻核心线程数,永远在的
	 	maximumPoolSize:
	 		最大线程数,阻塞队列满了,核心线程还没释放,这时候又来任务了,放不下了,就开始扩容,直至最大线程数
	 	keepAliveTime:
	 		线程存续时间,假如超过了这个时间,而且并没有再用到那么多的线程,超出corePoolSize部分的线程会被销毁
	 	unit:
	 		keepAliveTime的时间单位
	 	workQueue:
	 		一个阻塞队列,待执行的任务
	 	threadFactory:
	 		线程工厂,用于创建线程的,一般用默认的就好,不必改动
	 	handler:
	 		拒绝策略,阻塞队列满了,而且已经开到最大线程数了,解不了活了,执行拒绝策略
	 */
	
	/*
	 	《阿里巴巴Java开发手册》里面不允许使用Executors工具类来创建线程池
	 	因为FixedThreadPool和SingleThreadPool的任务队列最大是Integer.MAX_VALUE
	 	而CacheThreadPool和ScheduledThreadPool的线程数量最大是Integer.MAX_VALUE
	 	它们都有可能OOM
	 */
	
	public static void main(String[] args) {
		//CPU核心数
		int num = Runtime.getRuntime().availableProcessors();
		System.out.println(num);
		//对于cpu密集型的任务,一般都会将最大线程数设置为cpu核心数+1
		ExecutorService threadPool = new ThreadPoolExecutor(2, num + 1, 2L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(3));
	}
	
	/*
	 	线程开到最大数量并且任务队列满了,又来了新任务,这时候就要使用拒绝策略了
	  	四大拒绝策略:
	  		AbortPolicy:
	  			这是默认的拒绝策略,直接给我爬,抛异常
	  		CallerRunPolicy:
	  			回退,哪个线程让你来的,你回去那让个线程执行你这个任务去
	  		DiscardPolicy:
	  			拒绝你了还没叼你,你都不知道自己被拒绝了,也不抛异常
	  		DiscardOldestPolicy:
	  			不抛弃你,把队列里等的时间最长的抛弃,喜新厌旧
	 */
}

你可能感兴趣的:(java,juc,可重入锁,lock,线程池,ThreadPool)