多线程高级编程(2)

1, 单例模式

package y.i.d;

/**
 * DCL就是doubel checked lock 双重检测锁
 * 这个demo 是单例的懒汉模式 (饿汉就是直接new好了对象,懒汉就是什么时候什么时候new)
 * 主要利用 synchronized volatile 和 dcl 来实现;
 * 第一步私有化 构造方法 是外部不能拿到 
 * 第二步  static 私有化变量 存储 实例
 * 第三步 static 写获取 实例的方法
 * 然后在这个基础上再来使得最终只有一个实例生成
 * */

public class DCLTest {
	
	private  DCLTest() { //第一步私有化 构造方法 是外部不能拿到 
		
	}
	// volatile 使代码最终完善,不会出现 多线程拿到空对象的情况
	private volatile  static DCLTest instance; // 第二步 私有化变量 存储 实例
	
	public static DCLTest getInstance() {
		if(null!=instance) { // dcl 提高效率
			return instance;
		}
		synchronized (DCLTest.class) { // 此处同步多线程 ,锁住模子;
			if(null==instance) { 
				instance = new DCLTest();// 假如new 要花很长时间 这个时候就会出现 第二个取得了空值的情况
			}	
		}
		return instance;
	}
	
	public static void main(String[]  args){
		Thread t1=new Thread(()-> {
			System.out.println(DCLTest.getInstance());
		});		
		t1.start();
		System.out.println(DCLTest.getInstance());	
	}

}

2,ThreadLocal 

package y.i.d;
/**
 * ThreadLocal 是各个线程的本地存储, 独立不干扰
 * 一般使用 private static 修饰
 * 
 * */

public class ThreadLocalTest {
	
	// 不设置初始值 
	// private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
	
	// 设置初始值1 
//	private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
//		protected Integer initialValue() {
//			return 200;
//		}
//	};
		
	// 设置初始值2 
	private static ThreadLocal<Integer> threadLocal =ThreadLocal.withInitial(()->200);
	
	
	public static void main(String[]  args){
		threadLocal.set(1000);
		System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get()); //1000
		new Thread(new MyRun(),"xiaoming").start();
	}
	
	static class MyRun implements Runnable{
		@Override
		public void run() {
			threadLocal.set(999);
			System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());// 999
		}
	}	 
	
	
}

 ThreadLocal 的上下文

package y.i.d;
/**
 * ThreadLocal 是各个线程的本地存储, 独立不干扰
 * 一般使用 private static 修饰
 * 
 * */

public class ThreadLocalTest {
	private static ThreadLocal<Integer> threadLocal =ThreadLocal.withInitial(()->200);
	public static void main(String[]  args){
		threadLocal.set(1000);
		new Thread(new MyRun(),"xiaoming").start(); // 线程起点
	}
	
	static class MyRun implements Runnable{
		public MyRun() {
			// 此处时由 main 起的 所以上下文依然是main的
			System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());// 1000
		}
		@Override
		public void run() {
			threadLocal.set(999);
			System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());// 999
		}
	}	 
	
	
}

 ThreadLocal的子类 InheritableThreadLocal   实现上下文继承,会从起点 拷贝一份数据给子线程

package y.i.d;
/**
 * ThreadLocal 是各个线程的本地存储, 独立不干扰
 * 一般使用 private static 修饰
 * 
 * */

public class ThreadLocalTest {
	
	// 子线程不会继承 起点  值null
	// private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
	// 子线程会继承 起点  值1000
	 private static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>(); 

	public static void main(String[]  args){
		threadLocal.set(1000);
		System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());
		new Thread(new MyRun(),"xiaoming").start(); 
	}
	
	static class MyRun implements Runnable{
		@Override
		public void run() {
			System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());
		}
	}	 
	
	
}

3,  可重入锁 ReentrantLock

锁大部分内置都是可重入的,如果一个线程 想要获取他已经持有的锁的时候 那么他会立即成功,同时 内部有一个计数器,count++, count ==0 锁释放。 如果没有这种机制,那么就发生死锁。

可重入锁 机制其实就是一个类  下面实现一下

不可重入锁

package y.i.d;


public class ReentrantLockTest {
	Lock lock ;
	
	public ReentrantLockTest() {
	 this.lock= new Lock();
	}
	
	public void a() throws InterruptedException {
		lock.lock(); // 占用了资源
		dst();
		lock.unLock();
	}
	
	public void dst() throws InterruptedException {
		lock.lock(); // 死锁
		// ...
		lock.unLock();
	}
	
	public static void main(String[]  args) throws InterruptedException{
		ReentrantLockTest r  = new ReentrantLockTest();
			r.a();
	}
	
	
}
class Lock{
	private boolean isLocked = false;
	
	public synchronized void lock() throws InterruptedException {
		while(isLocked) {
			this.wait();
		}
		isLocked = true;
	}
	
    public synchronized void unLock() {
    	isLocked = false;
    	notify();
	}
	
}

可重入锁

package y.i.d;


public class ReentrantLockTest {
	Lock lock ;
	
	public ReentrantLockTest() {
	 this.lock= new Lock();
	}
	
	public void a() throws InterruptedException {
	
		lock.lock(); 
		System.out.println(lock.getCount());
		dst();
		lock.unLock();
		System.out.println(lock.getCount());
	}
	
	public void dst() throws InterruptedException {
		lock.lock(); 
		System.out.println(lock.getCount());
		// ...
		lock.unLock();
		System.out.println(lock.getCount());
	}
	
	public static void main(String[]  args) throws InterruptedException{
		ReentrantLockTest r  = new ReentrantLockTest();
			r.a();
	}
	
	
}
class Lock{
	private boolean isLocked = false;
	private int count = 0;
	private Thread thread = null;
	public synchronized void lock() throws InterruptedException {
		Thread t1 = Thread.currentThread();
		while(isLocked && thread!=t1) {
			this.wait();
		}
		count++;
		isLocked = true;
		thread = t1;
	}
	
    public synchronized void unLock() {
    	if(thread  ==Thread.currentThread()) {
    		count--;
    		if(count==0) {
    			isLocked = false;
    	    	notify();
    	    	thread=null;
    		}
    	}
    	
	}
    public int getCount() {
		return count;
	}
	
}

4,乐观锁 CAS

锁的分类有很多种 

按照可沿用性 可以分为 可重入锁 和 非可重入锁;

按照公平性,可以分为公平锁 和 不公平锁;

按照加锁不加锁 可以分为 悲观锁和乐观锁; 

悲观锁加锁,然后等锁解除才有后续操作;

乐观锁 就是不加锁,每次都去重新尝试 操作,失败了就重试知道成功位置;

乐观锁一般使用CAS来实现,Compare and swap 比较并且交换 ;

就是要更新一个值v, 比较 原来的值a,如果原来的值a对上了就更新 这个值v;

但是会存在ABA的问题;所以需要加版本控制一下;

就比较 版本 和 值 ,如果版本对上了,更新值并且 更新版本,

CAS属于原子操作;不会被外部打断;实现属于cpu 级别的硬件实现;效率很高

package y.i.d;

import java.util.concurrent.atomic.AtomicInteger;

public class CAS {
	// Atomic * 就是CAS来实现的
	private static AtomicInteger stock =  new AtomicInteger(5);
	public static void main(String[]  args){
		for (int i = 0; i < 6; i++) {
			new Thread(()->{
				// stock.decrementAndGet() 是CAS操作 减法 -1
				Integer left = stock.decrementAndGet();
				if(left<0) { // 有歧义
					System.out.println(Thread.currentThread().getName()+"没抢到"+left);
					return;
				}
				System.out.println(Thread.currentThread().getName()+"-->"+"抢到一件商品"+"还剩"+left+"件商品");
			}) .start();

		}
	}
}
发布了189 篇原创文章 · 获赞 10 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wangrong111222/article/details/102648907
今日推荐