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();//把结果进行合并操作
}
}
}