多线程-synchronized AQS 线程池 Atomic ThreadLocal volatile

1.java并发包括

①synchronized(保证数据可见性原子性)
②volatile(防止JVM指令重排;指示变量共享不稳定需要每次都从内存中获取从而保证变量可见性)
③threadLoocal(底层是threadLoocalMap.put(当前线程,值)
④线程池(作用:降低资源消耗,提高响应速度,提高线程可管理性, executor.execute(new MyRunnable(""+i))😉
⑤Atomic(
AtomicInteger:getAndSet(int newValue)
getAndIncrement()//获取当前的值,并自增
getAndDecrement() //获取当前的值,并自减
compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)
getAndAdd(int delta) //获取当前的值,并加上预期的值

AtomicInteger 类主要利用CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。
)
⑥AQS( CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中。状态信息通过 protected 类型的 getState,setState,compareAndSetState 进行操作
tryAcquire(int)//独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int)//独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int)//共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int)//共享方式。尝试释放资源,成功则返回true,失败则返回false。

)

PS:并发编程:原子性 有序性 可见性

2.synchronized

(1)认识:

重量级锁,synchronize保证同一时刻只有一个线程执行,因为synchronize依赖于底层的操作系统的 Mutex Lock 来实现的,线程上下文切换需要从用户态转换到内核态,这需要操作系统完成,因此耗时较大

(2)synchronized使用:

①加在静态方法

synchronized static void method() {
    //业务代码
}

②加在静态代码块

synchronized (this) {
    //业务代码
}

③普通方法

synchronized void method() {
    //业务代码
}

(3)synchronized底层实现

synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。

3.AQS

Exclusive(独占):只有一个线程能执行,如 ReentrantLock

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

public class ReentrantLockDemo {
//默认false ,false代表非公平锁
private static final Lock lock=new ReentrantLock(true);
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(int i=1;i<8;i++)
		{
			new Thread(()->test(),"线程"+i).start();
		}
		
		
	}
public static void test()
{
	
	
	try {
		lock.lock();
		System.out.println(Thread.currentThread().getName()+" try to lock");
		TimeUnit.SECONDS.sleep(2);
//		Thread.sleep(100);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally
	{
		System.out.println(Thread.currentThread().getName()+" release lock");
		lock.unlock();
	}
	
}
}

Share(共享):多个线程可同时执行,如 CountDownLatch、Semaphore、 CyclicBarrier、ReadWriteLock

(1)CountDownLatch(等待线程数量足够时才往下执行)

import java.util.concurrent.CountDownLatch;


public class CountDownLatchdemo {
	static CountDownLatch countDownLatch = new CountDownLatch(5);
    public static void main(String[] args) throws InterruptedException {
	for (int i = 0; i < 10; i++) {
	  
	    new Thread(() -> {
	        try {
	            Thread.sleep(10000);
	            System.out.println(Thread.currentThread().getName()+"开始等待");
	         
	            countDownLatch.countDown();//计数器-1
	             System.out.println("计数器"+countDownLatch.getCount());
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
	    }).start();
	}

	countDownLatch.await();// 主线程在阻塞,当计数器==0,就唤醒主线程往下执行。
	System.out.println("当前等待线程数量已达到5即计数器为0,开始往下执行");
}
}

(2)Semaphore(同一时刻多个线程执行)

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

public class SemaphoreDemo {
private static final Semaphore sp=new Semaphore(10);
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(int i=1;i<18;i++)
		{
			new Thread(()->test(),"线程"+i).start();
		}
		
		
	}
public static void test()
{
	
	
	try {
	
		System.out.println(Thread.currentThread().getName()+" try to lock");
		sp.acquire();
		TimeUnit.SECONDS.sleep(20);
//		Thread.sleep(100);
		System.out.println("并发线程数量="+(10-sp.availablePermits())+";queue length="+sp.getQueueLength());
		System.out.println("开始执行业务逻辑中.......");
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally
	{
		System.out.println(Thread.currentThread().getName()+" release lock");
		sp.release();
	}
	
}
}

(3) CyclicBarrier

其实和CountDownLatch蛮像的,不过CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
为什么说CountDownLatch 是一次性的呢?看下图CountDownLatch 运行效果图,
"当前等待线程数量已达到5即计数器为0,开始往下执行"这句话只执行了一次,也就是说计数器到0之后不会重新变成5
在这里插入图片描述

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierdemo {
	static int CyclicBarrier_capacity=5;
	static CyclicBarrier CB = new CyclicBarrier( CyclicBarrier_capacity);
    public static void main(String[] args) throws InterruptedException {
	for (int i = 0; i <  2*CyclicBarrier_capacity; i++) {
	  
	    new Thread(() -> {
	        try {
//	            Thread.sleep(1000);
	            System.out.println(Thread.currentThread().getName()+"开始等待"+"等待数量"+ CB.getNumberWaiting()+";parties="+CB.getParties());
	            CB.await();
	            System.out.println("当前等待线程数量已达到5即计数器为0,开始往下执行");
	           
	            
	        } catch (InterruptedException | BrokenBarrierException e) {
	            e.printStackTrace();
	        }
	    }).start();
	}
}
}

PS:注意比较CountDownLatch和CyclicBarrier:
(1) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
(2) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。

演示效果:

(1)运行 CountDownLatchdemo,到了后面计数器一直为0
在这里插入图片描述
(2)运行CyclicBarrierdemo,可见计数器没有一直为0,而是0->4周期性变化
在这里插入图片描述

https://www.cnblogs.com/skywang12345/p/3533995.html

(4)ReadWriteLock

以ReetrantReadWriteLock演示

private static ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
//四种方法
//加写锁
rwl.writeLock().lock();
//释放写锁
rwl.writeLock().unlock();
//加读锁
 rwl.readLock().lock();
//释放读锁
 rwl.readLock().unlock();
完整代码

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


public class ReentrantReadWriteLockDemo {
private static ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
	public static void main(String[] args) {
		ExecutorService es=Executors.newCachedThreadPool();
		//开启2个线程,1个执行读操作 1个执行写操作
		es.execute(new Runnable()
				{

					@Override
					public void run() {
						// TODO Auto-generated method stub
						myreadlock(Thread.currentThread());
					}
			
				}
				);
		
es.execute(new Runnable() {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		writemylock(Thread.currentThread());
	}
	
}
		
		
		);
	}
	
	
	
	//写锁具体实现
	protected static void writemylock(Thread currentThread) {
		// TODO Auto-generated method stub
		rwl.writeLock().lock();
		
		if(!rwl.isWriteLocked()) 
			{
			System.out.println("写锁");
			}//end if
		try {
			//处理事务
			for(int i=0;i<3;i++)
			{
				Thread.sleep(10);
				System.out.println(Thread.currentThread().getName()+"写入数据"+i);
			}//end for
			}//end try
		catch(Exception e) {}
			finally {
			//事务执行完释放锁
			rwl.writeLock().unlock();
			System.out.println("事务执行完释放写锁");}//end finally
		
		
		
		
		
		
		
		
	}
	
	//读锁具体实现
	protected static void myreadlock(Thread currentThread) {
		// TODO Auto-generated method stub
		rwl.readLock().lock();
		if(!rwl.isWriteLocked())
		{
		System.out.println("没有写锁可以加上读锁");
	    
		}// end if
		try {
		//处理事务
		for(int i=0;i<3;i++)
		{
			Thread.sleep(10);
			System.out.println(Thread.currentThread().getName()+"读数据"+i);
		}//end for
		}catch(Exception e) {}
		finally {
		//事务执行完释放锁
		rwl.readLock().unlock();
		System.out.println("事务执行完释放读锁");}//end finally
	}

}
总结ReetrantReadWriteLock

①.Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性
②.ReetrantReadWriteLock读写锁的效率明显高于synchronized关键字
③ReetrantReadWriteLock读写锁的实现中,读锁使用共享模式;写锁使用独占模式,换句话说,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的
④ReetrantReadWriteLock读写锁的实现中,需要注意的,当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁

作者:itbird01
链接:https://www.jianshu.com/p/9cd5212c8841
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

4.线程池

5.Atomic

6.ThreadLocal

7.volatile

8.扩展

hshamap->concurrenthashmap
arraylist-> CopyOnWriteArrayList

//编译
javac D:\eclipse-javaweb\eclipse-woekspace\Exam\src\com\multRunnable\SynchronizedDemo.java
//反汇编
javap -c -s -v -l D:\eclipse-javaweb\eclipse-woekspace\Exam\src\com\multRunnable\SynchronizedDemo.class
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值