JUC多线程

1. 读写锁 ReadWriteLock

  • 读读之间不需要互斥 ,读写 写写之间需要互斥
  • 通过readWriteLock.readLock().lock();//上锁 readWriteLock.readLock().unlock();//解锁 readWriteLock.writeLock().lock();//上锁 readWriteLock.writeLock().lock();//解锁
  • ReadWriteLock也是一个接口,具体实现:ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    具体代码实现:
/*
 * 1.ReadWriterLock:读写锁
 * 写写/读写--要进行“互斥”  读读不需要“互斥”
 */
public class TestReadWriterLock {
	public static void main(String[] args) {
		ReadWriterLockDemo readWriterLockDemo=new ReadWriterLockDemo();
		new Thread(new Runnable() {
			@Override
			public void run() {
				readWriterLockDemo.set((int)(Math.random()*101));
			}
		},"Write").start();
		for (int i = 0; i < 100; i++) {
			new Thread(new Runnable() {		
				@Override
				public void run() {
					readWriterLockDemo.get();
				}
			}).start();
		}
	}
}
class ReadWriterLockDemo{
	private int number=0;
	private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
	//读
	public void get() {
		readWriteLock.readLock().lock();//上锁
		try {
			System.out.println(Thread.currentThread().getName()+" :"+number);
		} finally {
			readWriteLock.readLock().unlock();
		}
	}
	//写
	public void set(int number) {
		readWriteLock.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName());
			this.number=number;
		} finally {
			readWriteLock.writeLock().unlock();
		}
	}
}

2. 线程八锁

  • 1.当两个普通同步的锁,标准打印 —>one two
/*
 * 判断 打印的是"one" or "two"
 */
public class TestThread8Monitor {
	public static void main(String[] args) {
		//1.当两个普通同步的锁,标准打印 --->one two
		Number number=new Number();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getOne();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getTwo();
			}
		}).start();
	}
}
class Number {
	public synchronized void getOne() {
		System.out.println("one");
	}
	public synchronized void getTwo() {
		System.out.println("two");
	}
}
  • 2.当给getOne()加上Thread.sleep()—>one two
	public synchronized void getOne() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("one");
	}
  • 3.当增加一个普通放入方法 getThree()时,会打印–>three one two
    public void getThree() { System.out.println("three"); }
  • 4.两个普通的同步方法 两个number对象 ---->two one
public static void main(String[] args) {
		//1.当两个普通同步的锁,标准打印 --->one two
		Number number=new Number();
		Number number2=new Number();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getOne();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number2.getTwo();
			}
		}).start();
//		new Thread(new Runnable() {
//			@Override
//			public void run() {
//				number.getThree();
//			}
//		}).start();
	}
}
class Number {
	public synchronized void getOne() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("one");
	}
	public synchronized void getTwo() {
		System.out.println("two");
	}
	public  void getThree() {
		System.out.println("three");
	}
}
  • 总结
  • 判断 打印的是"one" or “two”
    *1.当两个普通同步的锁synchronized,标准打印 —>one two
    *2.当给getOne()加上Thread.sleep()—>one two
    *3.当增加一个普通放入方法 getThree()时,会打印–>three one two
    *4.两个普通的同步方法 两个number对象 ---->two one
    *5.修改getOne()为static同步方法 一个number对象–>two one
    *6.修改getOne(),getTwo()为static同步方法 ,一个number对象 -->one two
    *7. getOne()静态同步,getTwo()非静态同步方法,两个number对象 —>two one
    *8. getOne()静态同步,getTwo()静态同步方法,两个number对象 —> one two
/*
 * 判断 打印的是"one" or "two"
 *1.当两个普通同步的锁synchronized,标准打印 --->one two
 *2.当给getOne()加上Thread.sleep()--->one two
 *3.当增加一个普通放入方法 getThree()时,会打印-->three  one two
 *4.两个普通的同步方法 两个number对象 ---->two one
 *5.修改getOne()为static同步方法  一个number对象-->two one
 *6.修改getOne(),getTwo()为static同步方法 ,一个number对象 -->one two
 *7. getOne()静态同步,getTwo()非静态同步方法,两个number对象 --->two one
 *8. getOne()静态同步,getTwo()静态同步方法,两个number对象 ---> one two
 *
 *线程八锁的关键:
 *		1)非静态方法的锁为this,静态方法的锁为对应的class实例
 *		2)某个时刻内,只能有一个线程持有锁,不管有几个方法
 */
public class TestThread8Monitor {
	public static void main(String[] args) {
		//1.当两个普通同步的锁,标准打印 --->one two
		Number number=new Number();
		Number number2=new Number();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getOne();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				//number.getTwo();
				number2.getTwo();
			}
		}).start();
//		new Thread(new Runnable() {
//			@Override
//			public void run() {
//				number.getThree();
//			}
//		}).start();
	}
}
class Number {
	public static synchronized void getOne() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("one");
	}
	public static synchronized void getTwo() {
		System.out.println("two");
	}
	public  void getThree() {
		System.out.println("three");
	}
}

3.线程池

  • 使用线程池的原因:
		ThreadPoolDemo threadPoolDemo=new ThreadPoolDemo();
		new Thread(threadPoolDemo).start();//启动线程
		//每次要使用线程是 必须呀创建一个线程 并启动,每次用过完 就会销毁 如果每次都创建 销毁就会很浪费资源

在这里插入图片描述
使用1:

	
		 //1.创建线程池 
		ExecutorService poolExecutorService = Executors.newFixedThreadPool(5);// 创建5个线程的线程池
		ThreadPoolDemo threadPoolDemo = new ThreadPoolDemo(); // 2.为线程池中的线程分配任务
		for (int i = 0; i < 10; i++) {
			poolExecutorService.submit(threadPoolDemo);
		} // 3.关闭线程池
		poolExecutorService.shutdown();// 等待当前线程完成就关闭线程 //
		poolExecutorService.shutdownNow();// 立即关闭

使用2:

		ExecutorService poolExecutorService = Executors.newFixedThreadPool(5);
		List<Future<Integer>> list = new ArrayList<Future<Integer>>();
		for (int i = 0; i <= 10; i++) {
			Future<Integer> futureTask = poolExecutorService.submit(new Callable<Integer>() {
				@Override
				public Integer call() throws Exception {
					int sum = 0;
					for (int i = 0; i <= 100; i++) {
						sum = sum + i;
					}
					return sum;
				}
			});
			list.add(futureTask);
		}
		for (Future<Integer> future : list) {
			System.out.println(future.get());
		}
		poolExecutorService.shutdown();
	}

4.线程池调度

  • ScheduledTreahExecutor newScheduledThreadPool():创建固定大小的线程,可以延迟或定时执行任务
  • Executors.newScheduledThreadPool(5);
mport java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/*
 * 1.线程池:提供了一个线程队列,队列中的保存着所有等待状态的线程。避免了创建与销毁的额外开销,提高了响应的速度
 * 2.线程池的体系结构:
 * 	java.util.concurrent.Executor:负责线程的使用与调用的跟接口
 *    |-- **ExecutorService 子接口:线程池的主要接口
 *       |-- ThreadPoolExecutor :线程池实现类
 *       |-- ScheduledExecutorService :子接口  负责线程的调度
 *       	|-- ScheduledTreahExecutor:继承了ThreadPoolExecutor,实现了ScheduledExecutorService
 * 3.工具类
 *ExecutorService  newFixedThreadPool():创建固定大小的连接池
 * ExecutorService newCachedThreadPool():缓存线程池,线程池的大小不固定,可以根据需求自动更改数量
 * ExecutorService newSingleThreadExecutor():线程池中只有一个线程池
 * 
 * ScheduledTreahExecutor newScheduledThreadPool():创建固定大小的线程,可以延迟或定时执行任务

 */

public class TestScheduledThreadPool {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ScheduledExecutorService pool=Executors.newScheduledThreadPool(5);
		for(int i=0;i<10;i++) {
			Future<Integer> res=pool.schedule(new Callable<Integer>() {
				@Override
				public Integer call() throws Exception {
					int num=new Random().nextInt(100);
					System.out.println(Thread.currentThread().getName()+" :"+num);
					return num;
				}
			}, 2, TimeUnit.SECONDS);//延迟3秒
			System.out.println(res.get());
		}
		pool.shutdown();
	}
}

分支合并框架 ForkJoinPool

  • JDK7出来的
  • Fork/join框架:在必要的情况下,将一个大的任务,进行拆分(fork)成若干个小的任务(拆到不可拆分时),再将一个个小的任务的运算结果进行join汇总
  • 多个线程同时跟多个小任务进行运算
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

import org.junit.Test;

public class TestForkJoinPool {
	public static void main(String[] args) {
		//因为拆分时需要时间的 
		Instant start=Instant.now();
		ForkJoinPool pool=new ForkJoinPool();//有它的支持才能正常运行
		ForkJoinTask<Long> forkJoinTask=new ForkJoinSumCalculate(0,1000000000L);
		Long sum=pool.invoke(forkJoinTask);//执行
		System.out.println(sum);
		Instant end=Instant.now();
		System.out.println("消耗的时间:"+Duration.between(start, end).toMillis());//
	}
	
	@Test
	public void test1() {//普通
		Instant start=Instant.now();
		long sum=0L;
		for(long i=0L;i<=1000000000L;i++) {
			sum+=i;
		}
		System.out.println(sum);
		Instant end=Instant.now();//获取现在的时间
		System.out.println("消耗的时间:"+Duration.between(start, end).toMillis());//		
	}
	
	@Test
	public void test2() {利用JDK8新特性来实现 拆分合并,对他进行了改进
		Instant start=Instant.now();
		long sum=LongStream.rangeClosed(0L, 1000000000L)
				.parallel()//并行流
				.reduce(0L, Long::sum);
		System.out.println(sum);
		Instant end=Instant.now();//获取现在的时间
		System.out.println("消耗的时间:"+Duration.between(start, end).toMillis());//		
	}
}
//以递归的方式 把大任务拆分成一个个的小任务
//RecursiveAction:没有返回值
//RecursiveTask<T>:有返回值
class ForkJoinSumCalculate extends RecursiveTask<Long>{
	private static final long serialVersionUID = 1L;
	private long start;
	
	private long end;
	private static final long THURSHOLD=10000L;//临界值 就是不能再拆分 thurshold
	
	public ForkJoinSumCalculate(long start,long end) {
		this.start=start;
		this.end=end;
	}
	public ForkJoinSumCalculate() {
	}
	@Override
	protected Long compute() {
	//拆分运算
		long len=end-start;
		if(len<=THURSHOLD) {//如果为临界值
			long sum=0L;
			for(long i=start;i<=end;i++) {//如果到达临界值 就直接运算总和
				sum+=i;
			}
			return sum;
		}else {//如果还能拆 就直接拆
			long middle=(start+end)/2;
			ForkJoinSumCalculate leftCalculate=new ForkJoinSumCalculate(start, middle);
			leftCalculate.fork();//进行拆分 同时压入线程队列
			ForkJoinSumCalculate rightCalculate=new ForkJoinSumCalculate(middle, end);
			rightCalculate.fork();//进行拆分	
			return leftCalculate.join()+rightCalculate.join();//把结果进行合并操作
		}	
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值