多线程和高并发(2)

synchronized, AtomicLong和LongAdder效率比较

在高并发下, AtomicLong比synchronized快. AtomicLong属于无锁.
而LongAdder又比AtomicLong快, LongAdder内部是分段锁, LongAdder在AtomicLong的基础上将单点的更新压力分散到各个节点,在高并发的时候通过分散提高了性能.

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

	public class Timecompare {
	static long count2 = 0L;
	static AtomicLong count1 = new AtomicLong();
	static LongAdder count3 = new LongAdder();
	public static void main(String[] args) {
		Thread[] threads = new Thread[1000];
		
		for(int i = 0;i<threads.length;i++) {
			threads[i]=new Thread(()->{
				for(int k=0;k<10000;k++)count1.incrementAndGet();
			});
				
			}
		try {
			long start = System.currentTimeMillis();//系统时间, 单位为毫秒
			
			for(Thread t:threads)t.start();
			for(Thread t:threads)t.join();
			long end = System.currentTimeMillis();
			System.out.println("Atomic:"+count1.get()+" time "+(end-start));
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
		
		
		//----------------------------------------------------------------
		Object lock = new Object();
		for(int i=0;i<threads.length;i++) {
			threads[i]=
					new Thread(new Runnable(){
						@Override
						public void run() {
							for(int k=0;k<10000;k++)
								synchronized(lock) {
									count2++;
								}
						}
					});
		}
		try {
			long start = System.currentTimeMillis();//系统时间, 单位为毫秒
			
			for(Thread t:threads)t.start();
			for(Thread t:threads)t.join();
			long end = System.currentTimeMillis();
			System.out.println("Synchronized :"+count2+" time "+(end-start));
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
		
		
		//--------------------------------------------------------------------
		for(int i=0;i<threads.length;i++) {
			threads[i] = new Thread(()->{
				for(int k=0;k<10000;k++)count3.increment();
			});
		}
		try {
			long start = System.currentTimeMillis();//系统时间, 单位为毫秒
			
			for(Thread t:threads)t.start();
			for(Thread t:threads)t.join();
			long end = System.currentTimeMillis();
			System.out.println("LongAdder :"+count3.longValue()+" time "+(end-start));
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
	}
}

Atomic:10000000 time 216
Synchronized :10000000 time 904
LongAdder :10000000 time 82
这种效率测试并不是十分准确.

ReentrantLock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
	Lock lock = new ReentrantLock();
	void m1() {
//		boolean locked = false;
		try {
			lock.lock();
//			locked = lock.tryLock(1,TimeUnit.SECONDS);
			for(int i = 0;i<6;i++) {
				TimeUnit.SECONDS.sleep(1);
				System.out.println(i);
			}}
			catch(InterruptedException e) {
				e.printStackTrace();
			}
			finally {
				lock.unlock();
			}
		}
	
	//使用trylock进行尝试锁,不管锁定与否,方法都将继续执行, 可以根据trylock的返回值来判断是否锁定,也可以指定trylock的时间,由于trylock(time)抛出异常,所以要注意unlock
	
	void m2(){
//		boolean locked = lock.tryLock();
//		if(locked)lock.unlock();
		boolean locked = false;
		try {
			locked = lock.tryLock(5,TimeUnit.SECONDS);
			System.out.println("m2..."+locked);
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
		finally {
			if(locked)lock.unlock();
		}
	
	}
	
	public static void main(String[] args) {
		lock01 l01 = new lock01();
		new Thread(l01::m1).start();
		try {
			TimeUnit.SECONDS.sleep(1);
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(l01::m2).start();
	}

}

lockInterruptibly

使用reentrantlock还可以调用lockInterruptibly方法,可以对线程interrupt方法作出相应.

可以被打断的加锁, lock.lockInterruptibly(); 可以对interrupt()方法做出相应.

	public static void main(String[] args) {
		Lock lock = new ReentrantLock();
		Thread t1 = new Thread(){
			public void run(){
				try {
					lock.lockInterruptibly(); 
					System.out.println("t1..."+locked);
			}
				catch(InterruptedException e) {
					e.printStackTrace();
			}
				finally {
					lock.unlock();
			}
		}};
		t1.start();
		try{
			Thread.sleep(10000); //等待10秒
		}
		catch(InterruptedException){
			e.printStackTrace();
		}
		t1.interrupt(); //打断t1的等待
	}

公平和非公平的切换

ReentrantLock默认是非公平锁

private static ReentrantLock lock = new ReentrantLock(true);//公平锁

ReentrantLock的底层实现也是cas

CountDownLatch

倒数门栓
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

	import java.util.concurrent.CountDownLatch;
	
	public static void main(String[] args) {
		
		usingCountDownLatch();
		usingJoin();
	}
	private static void usingCountDownLatch() {
		Thread[] threads = new Thread[100];
		CountDownLatch latch = new CountDownLatch(threads.length);
		
		for (int i = 0; i < threads.length; i++) {
			 threads[i] = new Thread(()->{
				int result = 0;
				for (int j = 0; j < 10000; j++) {
					latch.countDown();  //等待每个线程结束时, latch.countDown()	等	
				}	
		});	
		}
		
		for (int i = 0; i < threads.length; i++) {
			threads[i].start(); 
		}
		
		try {  //作用: 等待某些线程结束
			latch.await();  //门栓在这里锁住门
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("latch结束");
	}
	
	private static void usingJoin() {
		Thread[] threads = new Thread[100];
		
		for (int i = 0; i < threads.length; i++) {
			threads[i] = new Thread(()->{
				int result = 0;
				for (int j = 0; j < 10000; j++) result +=j;
		});	
		}
		
		for (int i = 0; i < threads.length; i++) {
			threads[i].start();
		}
		
		for (int i = 0; i < threads.length; i++) {
			try {
				threads[i].join();
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("join 结束");
	}
	    public void countDown()
  递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.
public boolean await(long timeout,TimeUnit unit) throws InterruptedException
  使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。
  如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直出于休眠状态:
  由于调用countDown()方法,计数到达零;或者其他某个线程中断当前线程;或者已超出指定的等待时间。
如果计数到达零,则该方法返回true值。
如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
如果超出了指定的等待时间,则返回值为false。如果该时间小于等于零,则该方法根本不会等待。
参数:
  timeout-要等待的最长时间
  unit-timeout 参数的时间单位
返回:
  如果计数到达零,则返回true;如果在计数到达零之前超过了等待时间,则返回false
抛出:
  InterruptedException-如果当前线程在等待时被中断

CyclicBarrier

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

	public class lock04 {
	public static void main(String[] args) {
		//CyclicBarrier循环栅栏, 什么时候人满了, 栅栏开启20个人出去了, 栅栏又关上等待下一波20人
		
		CyclicBarrier barrier = new CyclicBarrier(20, new Runnable(){//第一个参数是当达到20时,调用runnable
			@Override
			public void run() { System.out.println("满人,发车");}
	});
//		CyclicBarrier barrier1 = new CyclicBarrier(20);//如果没有runnable,就只是单纯的等20人就开启栅栏
//		CyclicBarrier barrier2 = new CyclicBarrier(20,()->System.out.println("满人,发车")); //lambda写法
	
	for (int i = 0; i < 100; i++) {
		new Thread(()->{
			try {//100个线程, barrier等待, 等栅栏开启然后启动, 20个线程一波
				barrier.await(); 
			}catch(InterruptedException e) {
				e.printStackTrace();
			}catch(BrokenBarrierException e) {
				e.printStackTrace();
			}
		}).start();
		
	}
	}

}

限流: 流量的入口很多, 限制出口Guava RateLimiter

读写锁

	import java.util.Random;
	import java.util.concurrent.locks.Lock;
	import java.util.concurrent.locks.ReadWriteLock;
	import java.util.concurrent.locks.ReentrantLock;
	import java.util.concurrent.locks.ReentrantReadWriteLock;

	public class lock06 {
	static Lock lock = new ReentrantLock();
	private static int value;
	static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //读写锁
	static Lock readLock = readWriteLock.readLock(); //当一个线程读的时候, 其他线程也能够读,理论上10个线程能同时完成读操作 脏读
	static Lock writeLock = readWriteLock.writeLock();
	
	public static void read(Lock lock) {
		try {
			lock.lock();
			Thread.sleep(1000);
			System.out.println("read over");
		}catch(InterruptedException e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
	
	public static void write(Lock lock,int v) {
		try {
			lock.lock();
			Thread.sleep(1000);
			value = v;
			System.out.println("write over");
		}catch(InterruptedException e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {
//		Runnable readR = ()->read(lock);
		Runnable readR = ()->read(readLock);
		
//		Runnable writeR = ()->write(lock,new Random().nextInt());
		Runnable writeR = ()->write(writeLock,new Random().nextInt());
		
		for (int i = 0; i < 10; i++) new Thread(readR).start();
		for (int i = 0; i < 2; i++) new Thread(writeR).start();
	}

}

Semaphore

最多允许多少个线程同时运行
限流
Semaphore的参数代表当前最多有多少个线程能同时执行

	import java.util.concurrent.Semaphore;
	public class lock07 {
	public static void main(String[] args) {
		Semaphore s = new Semaphore(1); //系统灯 几个信号灯 参数是1,当前时刻最多只能执行一个, 参数为2,当前最多两个线程同时执行
		//Semaphore s = new Semaphore(2,true);//设置为公平锁
		
		new Thread(()->{
			try {
				s.acquire();//阻塞方法, 信号灯是1 ,s.acquire()之后信号灯变成0, 别的线程就无法acquire
				System.out.println("t1 running");
				Thread.sleep(200);
				System.out.println("t1 running");
				
			}catch(InterruptedException e) {
				e.printStackTrace();
			}finally {
				s.release(); //又把信号灯从0变为1
			}
	}).start();
		
		new Thread(()->{
			try {
				s.acquire();
				System.out.println("t2 running");
				Thread.sleep(200);
				System.out.println("t2 running");
				
				
			}catch(InterruptedException e) {
				e.printStackTrace();
			}finally {
				s.release();
			}
	}).start();
	}

}

Exchanger

exchanger()方法 阻塞
只能是两个线程之间

	import java.util.concurrent.Exchanger;
	public class lock08 {
	static Exchanger<String> exchanger = new Exchanger<>();
	public static void main(String[] args) {
		new Thread(()->{
			String s = "T1";
			try {
				s = exchanger.exchange(s);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+" "+ s);
	},"t1").start();
		new Thread(()->{
			String s = "T2";
			try {
				s = exchanger.exchange(s);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+" "+ s);
	},"t2").start();
	}
}

t1线程的字符串T1被交换器阻塞, 等待另一个线程t2的字符串T2来交换. 如果没有另一个线程来进行交换, 那么t1线程会一直等待下去.

LockSupport

locksupport就好比wait方法, 但又不需要像syn那样上锁

	import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class lock09 {
	public static void main(String[] args) {
		Thread t = new Thread(()->{
			for(int i =0;i<10;i++) {
				System.out.println(i);
				if(i == 5) {
					LockSupport.park(); //当前线程阻塞  关门
				}
				try {
				TimeUnit.SECONDS.sleep(1);
				}catch(InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		t.start();
//		LockSupport.unpark(t);  //开门, park不用等待
		try {
		TimeUnit.SECONDS.sleep(8);
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("after 8 senconds!");
		LockSupport.unpark(t);  //指定唤醒某个阻塞的线程   unpark可以先于park调用  part启动比较靠后, unpart在线程启动后直接启动时,park是没效果的
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值