Java---多线程04

1.volatile----轻量级的synchronized锁  ,锁的是数据,保证线程之间变量的可见性,简单地说就是当线程A对变量x进行了修改之后,在线程A后面执行的其他线程能看到变量x的变动,volatile保证了数据永远是最新的,更详细地说是要符合以下两个规则:

     F.线程对变量进行修改之后,要立刻回写到主内存

     S.线程对变量进行读取的时候,要从主内存中读取,而不是缓存

        出于性能的考虑,当几个线程同时进行的时候,上一个线程修改的数据可能并没有写回到内存中进行修改,而这时下一个线程可能就需要读取到这个数据,那么这个数据便不是最新的数据,这时volatile便发挥了用处,它保证了线程数据的同步。

volatile是不错的机制,但是不能保证原子性:例如a++这个指令在计算机执行的时候会分成3条:首先取出a,然后执行a+1,最后存回到a,volatile不能保证这三条语句一起执行。

package cn.MulThreadOthers.java.mhz;
/**
 * volatile用于保证线程数据的同步性,也就是可见性
 * @author MHZ
 *
 */
public class MyJavaMulThreadVolatile {
	private volatile static int num  = 0;
	public static void main(String[] args) throws InterruptedException {
		new Thread(()->{
			while(num==0) {
				
			}
		}).start();
		Thread.sleep(1000);
		num = 1;
	}
}

2.DCL单例设计模式

package cn.MulThreadOthers.java.mhz;

/**
 *  DCL 单例设计模式
 *      单例设计模式 :在多线程环境下,对外存在一个对象
 *      1.构造器私有化 --- >避免外部new构造器
 *      2.提供私有的静态属性--->存储对象的地址
 *      3.提供公共的静态方法--->获取属性
 * @author MHZ
 *
 */
public class MyJavaDoubleCheckedLocked {
	
	//1.构造器私有化
	private MyJavaDoubleCheckedLocked()
	{
		
	}
	
	//2.提供私有的静态属性
	private static volatile MyJavaDoubleCheckedLocked instance;
	
	//3.提供公共的静态方法--->获取属性
	public static MyJavaDoubleCheckedLocked getinstance()
	{
		//再次检测   节省时间
		if(null!=instance) {
			return instance;
		}
		synchronized(MyJavaDoubleCheckedLocked.class)
		{
			if(instance==null) {
				//开辟空间    初始化对象信息   将对象的地址返回给引用
				//上面为new一个对象时所做的事
				//new这个对象的时候,可能会出现指令重排现象,这是由于初始化对象信息比较慢,cpu可能会先执行第3步,这样会导致线程返回一个错误的引用
				//使用轻量级的锁(数据锁)violate来避免指令重排带来的错误,形成各个线程的数据可见
				instance = new MyJavaDoubleCheckedLocked();
			}
		}
		return instance;
	}
	
	public static void main(String[] args) {
		Thread t = new Thread(()->{
			System.out.println(MyJavaDoubleCheckedLocked.getinstance());
		});
		t.start();
		
		System.out.println(MyJavaDoubleCheckedLocked.getinstance());
	}
}

3.可重入锁

如果对象试图获得一个已经由它自己持有的锁时,那么这个请求会立刻成功,并且将这个锁的计数值加1,当线程退出同步代码块的时候,计数值将会递减,当计数值为0时,锁释放;大多数系统内置锁都是可重入锁,可以延续使用

package cn.MulThreadOthers.java.mhz;
/**
 * 	如果对象试图获得一个已经由它自己持有的锁时,那么这个请求会立刻成功,并且将这个锁的计数值加1,当线程退出同步代码块的时候,计数值将会递减,当计数值为0时,锁释放
 * 	可重入锁,大多数内置锁都是可重入锁    锁可以重复使用
 * @author MHZ
 *
 */
public class LockTest {
	public void test()
	{
		//第一次获得锁
		synchronized(this) {
			//第二次获得同样的锁,这就是可重入锁,可延续,调用自己的锁不会出现死锁
			while (true) {
				synchronized (this) {
					System.out.println("ReLock");
				}

				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public synchronized void a()
	{
		System.out.println("first");
	}
	
	public synchronized void b()
	{
		System.out.println("second");
	}
	
	public void all()
	{
		//当前对象已经获得锁
		synchronized(this)
		{
			//如果当前对象已经获得锁,那么它试图获得一个由它自己持有的锁,这个请求会立刻被执行
			this.a();
			this.b();
		}
	}
	
	public static void main(String[] args) {
		//new LockTest().test();
		LockTest l = new LockTest();
		l.a();
		l.b();
		l.all();
	}
}

手动实现的不可重入锁

package cn.MulThreadOthers.java.mhz;
/**
 * 	 不可重入锁,会形成死锁				无法延续锁
 * @author MHZ
 *
 */
public class LockTest01 {
	Lock lock = new Lock();
	public void a() throws InterruptedException {
		lock.lock();
		doSomething();
		lock.unlock();
	}
	//不可重入
	public void doSomething() throws InterruptedException {
		lock.lock();
		//...................
		lock.unlock();
	}
	public static void main(String[] args) throws InterruptedException {
		LockTest01 test = new LockTest01();
		test.a();
		test.doSomething();
	}
}

// 不可重入锁
class Lock{
	 
	//是否占用
	private boolean isLocked = false;
	
	//使用锁
	public synchronized void lock() throws InterruptedException {
		while(isLocked) {
			wait();
		}
		isLocked = true;
	}
	
	//释放锁
	public synchronized void unlock() {
		isLocked = false;
		notify();
	}
	
}

手动实现的可重入锁,加入了计数器

package com.sxt.others;
/**
 * 可重入锁: 锁可以延续使用 + 计数器
 * 
 * @author MHZ
 *
 */
public class LockTest02 {
	ReLock lock = new ReLock();
	public void a() throws InterruptedException {
		lock.lock();
		System.out.println(lock.getHoldCount());
		doSomething();
		lock.unlock();
		System.out.println(lock.getHoldCount());
	}
	//可重入     可延续
	public void doSomething() throws InterruptedException {
		lock.lock();
		System.out.println(lock.getHoldCount());
		//...................
		lock.unlock();
		System.out.println(lock.getHoldCount());
	}
	public static void main(String[] args) throws InterruptedException {
		LockTest02 test = new LockTest02();
		test.a();			
		Thread.sleep(1000);		
		System.out.println(test.lock.getHoldCount());
	}

}
// 可重入锁
class ReLock{
	//是否占用
	private boolean isLocked = false;
	private Thread lockedBy = null; 		//存储线程
	private int holdCount = 0;				//计数器
	//使用锁
	public synchronized void lock() throws InterruptedException {
		Thread t = Thread.currentThread();
		while(isLocked && lockedBy != t) {
			wait();
		}
		
		isLocked = true;
		lockedBy = t;
		holdCount ++;
	}
	//释放锁
	public synchronized void unlock() {
		if(Thread.currentThread() == lockedBy) {
			holdCount --;
			if(holdCount ==0) {
				isLocked = false;
				notify();
				lockedBy = null;
			}		
		}		
	}
	public int getHoldCount() {
		return holdCount;
	}
}

ReentrantLock是系统自带的可重入锁,可以直接使用

package com.sxt.others;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁   ReentrantLock
 * @author MHZ
 *
 */
public class ReenLock {
	ReentrantLock lock = new ReentrantLock();
	public void a() throws InterruptedException {
		lock.lock();
		System.out.println(lock.getHoldCount());
		doSomething();
		lock.unlock();
		System.out.println(lock.getHoldCount());
	}
	//可重入     可延续
	public void doSomething() throws InterruptedException {
		lock.lock();
		System.out.println(lock.getHoldCount());
		//...................
		lock.unlock();
		System.out.println(lock.getHoldCount());
	}
	public static void main(String[] args) throws InterruptedException {
		ReenLock test = new ReenLock();
		test.a();			
		Thread.sleep(1000);		
		System.out.println(test.lock.getHoldCount());
	}

}

4.CAS原子操作

CAS是实现乐观锁的一种方式,乐观锁是指每次不加锁而是假设不冲突去完成某项工作,如果发生冲突就失败,并一直重试,直到成功为止

有可能出现ABA问题

package com.sxt.others;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 比较并交换
 * CAS原子操作          是实现乐观锁的一种方式:每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止
 * 有可能出现ABA问题,ABA问题是指变量V初次读取的值是A,但是这不能说明一开始就是A,可能是别的线程修改成B再改成A,这时候CAS并不能知晓
 * @author MHZ
 *
 */
public class CAS {
	//库存         原子操作都使用了CAS的思想
	private static AtomicInteger stock = new AtomicInteger(5);
	
	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			Integer left = stock.decrementAndGet();
			//System.out.println((int)left);
			new Thread(() -> {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				//Integer left = stock.decrementAndGet();
				//System.out.println(left);
				if(left<1) {
					System.out.println("抢完了...");
					return;
				}
				System.out.print(Thread.currentThread().getName()+"抢了一个商品     ");
				System.out.println("还剩下"+"--->"+left);
			}).start();
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值