JUC相关测试学习代码

本文通过一系列测试代码深入探讨Java并发编程,包括自旋锁的实现、volatile特性的验证、synchronized与ReentrantLock的可重入性、ArrayList的线程不安全性、读写锁的使用,以及JUC组件如CountDownLatch、CyclicBarrier、Semaphore和SynchronousQueue的实战演示。此外,还涉及多线程间的顺序调用、生产者消费者模式、线程池的实现以及死锁的模拟。最后,简要总结了垃圾收集器的配置。
摘要由CSDN通过智能技术生成

手写一个自旋锁(底层是CAS)

主要就是获得锁lock()的地方应用了CAS

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/*
 * 手写一个自旋锁(底层是CAS)
 */

public class SpinlockDemo {

	// 原子引用,解决JMM中原子性问题,底层是unsafe类,其下面的各个方法是CAS在java中的体现
	AtomicReference<Thread> reference = new AtomicReference<Thread>();

	public void lock() {
		Thread thread = Thread.currentThread();
		System.out.println(Thread.currentThread().getName() + "\t 来了! ");
		do {
			// 循环
		} while (!reference.compareAndSet(null, thread));

	}

	private void unlock() {
		Thread thread = Thread.currentThread();
		System.out.println(Thread.currentThread().getName() + "\t 释放了锁! ");
		reference.compareAndSet(thread, null);

	}

	public static void main(String[] args) {
		SpinlockDemo spinlockDemo = new SpinlockDemo();

		new Thread(() -> {
			spinlockDemo.lock();
			// System.out.println(Thread.currentThread().getName() + "\t 来了! ");
			try {
				TimeUnit.SECONDS.sleep(3);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			spinlockDemo.unlock();
			// System.out.println(Thread.currentThread().getName() + "\t 释放了锁!
			// ");

		}, "first").start();

		new Thread(() -> {
			spinlockDemo.lock();//如果first不释放锁,这个second就一直在这里自旋
			System.out.println(Thread.currentThread().getName() + "\t 终于轮到我了! ");
			spinlockDemo.unlock();

			// System.out.println(Thread.currentThread().getName() + "\t 释放了锁!
			// ");

		}, "second").start();

	}

}

输出:
first	 来了! 
second	 来了! 
first	 释放了锁! 
second	 终于轮到我了! 
second	 释放了锁! 

单例模式,DCL版+volatile禁止重排


/*
 * 单例模式,DCL版+volatile禁止重排
 */

public class Singleton {

	// 这个地方是懒汉式,如果下面没有if判断,就是饿汉式,防止面试问到
	// 这里加volatile是为了防止指令重排
	private static volatile Singleton instance = null;

	// 精髓之处,将constructor私有化
	private Singleton() {
		System.out.println("dddd");
	}

	public static Singleton getInstance() {
		if (instance == null) {
			// 这里的synchronized是DCL双重锁检测,
			// 就像去房间,先敲门,进去了再按按门,看有没有锁严实,再做事
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}

		}
		return instance;

	}
	
	//test
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(()->Singleton.getInstance(),String.valueOf(i)).start();;
			
		}	
		
		
	}

}

测试volatile保证可见性

import java.util.concurrent.TimeUnit;

/*
 * 测试volatile保证可见性
 */

public class Seeable {

	// 外部类可以通过实例访问内部类的私有变量
	static class MyData {
		private int num = 0;
		// private volatile int num = 0; 此处加上volatile保证可见性

		public void changeData() {
			this.num = 10;
		}

	}

	public static void main(String[] args) {
		MyData myData = new MyData();

		// 乃木达表达式,期间用TimeUnit让线程休眠3秒
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				TimeUnit.SECONDS.sleep(3);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			// 改变数据
			myData.changeData();

			System.out.println("num = " + myData.num);

		}, "Ding").start();

		// 如果num没有用colatile修,那么mian和Ding线程之间是不可见的,对于main来说,num一直为0,就会一直在这里循环,出不去
		while (myData.num == 0) {

		}
		// 如果num加了volatile修饰,就会执行到这里,并打印这句话
		System.out.println(Thread.currentThread().getName() + " mission complete");

	}

}

测试volatile不保证原子性

import java.util.concurrent.atomic.AtomicInteger;

/*
 * 测试volatile不保证原子性
 */

class MyData {
	volatile int num = 1;

	public void addNum() {
		num++;
	}

	// 因为colatile不保证原子性,这里用JUC里面的AtomicInteger类,构造函数里面的值是初始化value,默认为0
	AtomicInteger atomicInteger = new AtomicInteger(1);

	public void atomicAddNum() {
		atomicInteger.getAndAdd(1); // 相当于i++,参数是每次加多少

	}

}

public class AtonicTest {

	public static void main(String[] args) {
		MyData myData = new MyData();

		for (int i = 0; i < 20; i++) {

			new Thread(() -> {
				for (int j = 0; j < 1000; j++) {
					// myData.addNum();
					// 这里用AtomicInteger类的方法,保证原子性
					myData.atomicAddNum();

				}

			}, String.valueOf(i)).start();

		}

		// 如果后台线程大于2(后台默认有一个main和GC线程),就让线程继续执行
		while (Thread.activeCount() > 2) {
			Thread.yield();
		}

		System.out.println("最终的num值是: " + myData.atomicInteger);

	}

}

测试syn可重入锁


/*
 * 测试syn可重入锁
 */

public class SynDemo {

	static class Phone {
		public synchronized void getName() {
			System.out.println(Thread.currentThread().getName() + "   getName");
			getId();
		}

		public synchronized void getId() {
			System.out.println(Thread.currentThread().getName() + "   getId");
		}

	}

	public static void main(String[] args) {
		Phone phone = new Phone();

		new Thread(() -> phone.getName(), "first").start();

		new Thread(() -> phone.getName(), "second").start();

	}

}

测试ReentrantLock可重入锁

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

/*
 * 测试ReentrantLock可重入锁
 */

public class ReentrantDemo {
	public static ReentrantLock lock = new ReentrantLock();

	public static void getName() {
		lock.lock();
		lock.lock();
		try {
			System.out.println(Thread.currentThread().getName() + "  getName()");
			getId();
		} finally {
			lock.unlock();
		}
	}

	public static void getId() {
		lock.lock();
		try {
			System.out.println(Thread.currentThread().getName() + "  getId()");
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) {

		new Thread(() -> getName(), "first").start();
		new Thread(() -> getName(), "second").start();
	}

}

ArrayList线程不安全示范:add方法没有加syn

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

/*
 * ArrayList线程不安全示范:add方法没有加syn
 */

public class ContainerNotSafeDemo {

	public static void main(String[] args) {
		
		//1、用vector:List<Integer> list = new Vector<Integer>();
		//2、用集合类Collections:List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
		List<Integer> list = new CopyOnWriteArrayList<Integer>();

		// 会引发并发修改异常:java.util.ConcurrentModificationException
		for (int i = 0; i < 30; i++) {
			new Thread(() -> {
				list.add(3);
				System.out.println(list);
			}).start();
		}
		
	}

}

测试读写锁

import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/*
 * 读写锁
 */

class Source {

	volatile HashMap<String, Object> map = new HashMap<String, Object>();
	//可重复写入的读写锁,只要是在写,其他线程都不能读或写
	ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();

	public void set(String str, Object obj) {
		try {
			rwlock.writeLock().lock();

			System.out.println(Thread.currentThread().getName() + "-正在写入:" + str);
			map.put(str, obj);
			System.out.println(Thread.currentThread().getName() + "-写入完成");

		} finally {

			rwlock.writeLock().unlock();
		}

	}

	public void get(String str) {

		try {
			rwlock.writeLock().lock();

			System.out.println(Thread.currentThread().getName() + "-正在读取");
			Object object = map.get(str);
			System.out.println(Thread.currentThread().getName() + "-读取完成" + object);
		} finally {

			rwlock.writeLock().unlock();
		}

	}

}

public class ReadWriteLockDemo {

	public static void main(String[] args) {

		Source source = new Source();
		for (int i = 0; i < 5; i++) {
			final int temp = i;
			new Thread(() -> {
				source.set(temp + "", temp + "");
			}, String.valueOf(i)).start();

		}
		// 睡眠2秒,保证写操作全部完成
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		for (int i = 0; i < 5; i++) {
			final int temp = i;
			new Thread(() -> {
				source.get(temp + "");
			}, String.valueOf(i)).start();

		}

	}

}

输出:
1-正在写入:1
1-写入完成
0-正在写入:0
0-写入完成
2-正在写入:2
2-写入完成
3-正在写入:3
3-写入完成
4-正在写入:4
4-写入完成
0-正在读取
0-读取完成0
2-正在读取
2-读取完成2
1-正在读取
1-读取完成1
4-正在读取
4-读取完成4
3-正在读取
3-读取完成3


JUC.CountDownLatch的测试Demo

首先创建一个枚举类:


/*
 * CountDownLatch的枚举类
 */

public enum StudentEnum {

	one(1, "赵"), two(2, "钱"), three(3, "孙"), fore(4, "李"), five(5, "周"), six(6, "吴");

	private Integer num;
	private String name;

	public Integer getNum() {
		return num;
	}

	public String getName() {
		return name;
	}

	private StudentEnum(Integer num, String name) {
		this.num = num;
		this.name = name;
	}

	public static StudentEnum forEach(int index) {
		StudentEnum[] enums = StudentEnum.values();
		for (StudentEnum studentEnum : enums) {
			if (studentEnum.getNum() == index) {
				return studentEnum;
			}
		}
		return null;

	}

}

再来测试类:

import java.util.concurrent.CountDownLatch;

/*
 *  CountDownLatch测试
 */

public class CountDownLatchDemo {
	
	static CountDownLatch countDownLatch = new CountDownLatch(6);
	
	public static void main(String[] args) throws InterruptedException {
		
		for (int i = 1; i <= 6 ; i++) {
			
			final int tem = i;
			new Thread(()->{
				System.out.println(StudentEnum.forEach(tem).getName() + "同学走了");
				countDownLatch.countDown();
			}).start();
		}
		
		countDownLatch.await();
		System.out.println(Thread.currentThread().getName() + ":############班长锁门");
		
		
	}
	
}



输出:

赵同学走了
孙同学走了
钱同学走了
周同学走了
吴同学走了
李同学走了
main:############班长锁门(不使用CountDownLatch的话,班长就不会在最后锁门了)


JUC.CyclicBarrier测试Demo

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

/*
 *  CyclicBarrierDemo
 */

public class CyclicBarrierDemo {

	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
			System.out.println("神龙,出来吧!");
		});

		for (int i = 1; i <= 7; i++) {
			final int temp = i;
			new Thread(() -> {
				System.out.println("收集到第" + temp + "个龙珠");

				//这里加一个await()方法,就可以在七颗龙珠还没有收集完之前都在等待
				try {
					cyclicBarrier.await();
				} catch (InterruptedException | BrokenBarrierException e) {
					e.printStackTrace();
				}
			}).start();
		}

	}
	
	输出:
	收集到第1个龙珠
	收集到第2个龙珠
	收集到第3个龙珠
	收集到第5个龙珠
	收集到第6个龙珠
	收集到第7个龙珠
	收集到第4个龙珠
	神龙,出来吧!


}

JUC.Semaphore的测试Demo

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

/*
 * SemaphoreDemo 
 */
public class SemaphoreDemo {

	public static void main(String[] args) {
		// 海底捞空3个座位
		Semaphore semaphore = new Semaphore(3);

		// 有6个人在等待
		for (int i = 1; i <= 7; i++) {

			new Thread(() -> {
				try {
					semaphore.acquire();
					System.out.println(Thread.currentThread().getName() + "获得座位");
					TimeUnit.SECONDS.sleep(3);// 吃饭三秒
					System.out.println(Thread.currentThread().getName() + "吃完走人");
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					semaphore.release();
				}

			},String.valueOf(i)).start();

		}

	}

}


输出:

1获得座位
2获得座位
3获得座位
3吃完走人
1吃完走人
2吃完走人
5获得座位
7获得座位
4获得座位
5吃完走人
7吃完走人
6获得座位
4吃完走人
6吃完走人

JUC.SynchronousQueue的测试Demo

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/*
 * SynchronousQueue测试
 */

public class SynchronousQueueDemo {

	// SynchronousQueue不存储数据,只能每次put一个,等到take了之后才能继续take

	public static void main(String[] args) {

		SynchronousQueue<Integer> synqueue = new SynchronousQueue<Integer>();

		new Thread(() -> {
			try {
				// 加入
				System.out.println(Thread.currentThread().getName() + " put 1");
				synqueue.put(1);

				System.out.println(Thread.currentThread().getName() + " put 2");
				synqueue.put(2);

				System.out.println(Thread.currentThread().getName() + " put 3");
				synqueue.put(3);

			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}, "first").start();

		new Thread(() -> {
			try {
				TimeUnit.SECONDS.sleep(3);
				System.out.println(Thread.currentThread().getName() + "拿到了:" + synqueue.take());

				TimeUnit.SECONDS.sleep(3);
				System.out.println(Thread.currentThread().getName() + "拿到了:" + synqueue.take());

				TimeUnit.SECONDS.sleep(3);
				System.out.println(Thread.currentThread().getName() + "拿到了:" + synqueue.take());

			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}).start();

	}

}

输出:

first put 1
Thread-0拿到了:1
first put 2
Thread-0拿到了:2
first put 3
Thread-0拿到了:3

题目:多线程之间顺序调用

要求如下:

AA打印5次,BB打印10次,CC打印15次
循环10轮

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

/*
 * 题目:顺序打印A-B-C
 * AA打印5次,BB打印10次,CC打印15次,然后循环10轮
 */

class Ding {
	private int flagNum = 1;
	private ReentrantLock lock = new ReentrantLock();
	private Condition c1 = lock.newCondition();
	private Condition c2 = lock.newCondition();
	private Condition c3 = lock.newCondition();

	private void print(int num) {
		for (int i = 1; i <= num; i++) {
			System.out.println(Thread.currentThread().getName() + "\t " + i);
		}
	}

	public void print5() {
		lock.lock(); // 加锁
		try {

			while (flagNum != 1) { // 如果flag不是1,等待
				c1.await();
			}
			print(5); // 打印5次
			flagNum = 2; // 将flag变为2
			c2.signal(); // 唤醒c2

		} catch (Exception e) {
		} finally {
			lock.unlock(); // 释放锁
		}

	}

	public void print10() {
		lock.lock();
		try {

			while (flagNum != 2) {
				c2.await();
			}
			print(10);
			flagNum = 3;
			c3.signal();

		} catch (Exception e) {
		} finally {
			lock.unlock();
		}
	}

	public void print15() {
		lock.lock();
		try {

			while (flagNum != 3) {
				c3.await();
			}
			print(15);
			flagNum = 1;
			c1.signal();

		} catch (Exception e) {
		} finally {
			lock.unlock();
		}
	}

}

public class LockConditionDemo {

	public static void main(String[] args) {
		Ding ding = new Ding();

		for (int i = 0; i < 5; i++) {
			new Thread(() -> {
				ding.print5();
			}, "AA").start();

			new Thread(() -> {
				ding.print10();
			}, "BB").start();

			new Thread(() -> {
				ding.print15();
			}, "CC").start();
		}

	}

}

自测小题目:A生产一个B消费一个

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

/*
 * 自测:A生产一个B消费一个
 */

class PrintOneByOneResource {
	private volatile Integer num = 1;
	
	ReentrantLock lock = new ReentrantLock();
	
	private Condition cpro = lock.newCondition();
	private Condition ccon= lock.newCondition();

	public void product() {
		lock.lock();
		try {
			
			while (num != 1) {
				cpro.await();
				
			}

			System.out.println(Thread.currentThread().getName() + "生产了一个");
			num = 2;
			ccon.signal();

		} catch (Exception e) {
		} finally {
			lock.unlock();
		}

	}

	public void consume() {
		lock.lock();
		try {
			while (num != 2) {
				ccon.await();				
			}

			System.out.println(Thread.currentThread().getName() + "消费了一个");
			num = 1;
			cpro.signal();
		} catch (Exception e) {
		} finally {
			lock.unlock();
		}

	}

}

public class PrintOneByOne {

	public static void main(String[] args) {
		PrintOneByOneResource source = new PrintOneByOneResource();
		for (int i = 0; i < 20; i++) {
			new Thread(() -> {
				source.product();

			}, "A").start();

			new Thread(() -> {
				source.consume();

			}, "B").start();
		}

	}

}

生产者消费者模式-阻塞队列版

要求:生产一个消费一个,然后可以停止(不用syn,不用锁,用阻塞队列和原子引用)

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/*
 * 生产者消费者模式-阻塞队列版
 * 要求:生产一个消费一个,然后可以停止
 * 
 */

class ProdConsResource {
	private volatile boolean flag = true; // 生产消费的flag

	private AtomicInteger atomicInteger = new AtomicInteger(); // 原子引用,用来做++i操作

	private BlockingQueue<String> blockingQueue; // 阻塞队列,这里用超时的方法 offer poll

	// 这里的BlockingQueue是一个接口,我们在资源类的constructor里面再定义
	public ProdConsResource(BlockingQueue<String> blockingQueue) {
		super();
		this.blockingQueue = blockingQueue;
	}

	public void product() throws InterruptedException {
		String data = null;
		boolean ret;
		while (flag) {
			data = atomicInteger.incrementAndGet() + "";
			ret = blockingQueue.offer(data, 2, TimeUnit.SECONDS);
			if (ret) {
				System.out.println(Thread.currentThread().getName() + "进入队列" + data + "成功");
			} else {
				System.out.println(Thread.currentThread().getName() + "进入队列失败" + data + "失败");

			}
			TimeUnit.SECONDS.sleep(1);
		}
		
	}

	public void consumer() throws InterruptedException {
		String result = null;
		while (flag) {
			result = blockingQueue.poll(2, TimeUnit.SECONDS);
			if (null == result || result.equalsIgnoreCase("")) {
				flag = false;
				System.out.println(Thread.currentThread().getName() + "超过俩秒中没有拿到蛋糕,消费停止");
				return;
			}
			

			System.out.println(Thread.currentThread().getName() + "从队列中消费" + result);
		}
		//这个地方实现先后消费是靠sleep(1),之前是靠唤醒,这个靠时间会不会有点问题?
		TimeUnit.SECONDS.sleep(1);

	}

	public void stop() {
		this.flag = false;
	}

}

public class ProdConsumerBlockQueueDemo {

	public static void main(String[] args) throws InterruptedException {
		ProdConsResource resource = new ProdConsResource(new ArrayBlockingQueue<String>(10));

		new Thread(() -> {

			try {
				resource.product();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}, "product").start();

		new Thread(() -> {

			try {
				resource.consumer();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}, "consumer").start();

		TimeUnit.SECONDS.sleep(5);
		System.out.println("boss拉闸");
		resource.stop();

	}

用ThreadPoolExecutor手写一个线程池

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo {
	public static void main(String[] args) {

		/*
		 * ExecutorService threadpool01 = Executors.newFixedThreadPool(5);
		 * ExecutorService threadpool02 = Executors.newSingleThreadExecutor();
		 * ExecutorService threadpool03 = Executors.newCachedThreadPool();
		 * ExecutorService threadpool04 = Executors.newScheduledThreadPool(3);
		 */

		ExecutorService threadpool = new ThreadPoolExecutor(3, 5, 1L, TimeUnit.SECONDS,
				new LinkedBlockingDeque<Runnable>(2), Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.DiscardOldestPolicy());

		for (int i = 1; i <= 10; i++) {

			threadpool.execute(() -> {
				System.out.println(Thread.currentThread().getName() + "处理了业务");

			});
		}

	}
}

手写一个死锁

/*
 * 手写一个死锁
 */
public class HoldThread {

	public static void main(String[] args) {

		String lockA = "AAA";
		String lockB = "BBB";

		new Thread(() -> {
			synchronized (lockA) {
				System.out.println(Thread.currentThread().getName() + "自己持有" + lockA + "他想要" + lockB);
				synchronized (lockB) {
					System.out.println(Thread.currentThread().getName() + "自己持有" + lockB + "他想要" + lockA);

				}
			}

		}, "first:").start();

		new Thread(() -> {
			synchronized (lockB) {
				System.out.println(Thread.currentThread().getName() + "自己持有" + lockB + "他想要" + lockA);
				synchronized (lockA) {
					System.out.println(Thread.currentThread().getName() + "自己持有" + lockA + "他想要" + lockB);
				}
			}

		}, "second:").start();

	}

}

輸出:

first:自己持有AAA他想要BBB
second:自己持有BBB他想要AAA

垃圾收集器配置总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值