1.线程中的函数式接口
函数式接口将Runnable接口中的run()方法重写为method()方法,下列代码测试两个线程分别对同一个集合中10个元素,最后获取集合的长度,由于线程不安全,最后集合长度的输出结果会小于20。
static List list = new ArrayList<>();
public static void method(){
for (int i=0;i<10;i++){
list.add("A"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Runnable run = EasyThreadA::method;//函数式接口
//使用EasyThreadA中的method替换Runnable中的run()方法
Thread a = new Thread(run);
Thread b = new Thread(run);
a.start();
b.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(list.size());
}
2.两个线程分别存入十个数据到数组中:
先创建一个继承Thread类的子类,在这个类中重写run()方法,使list中存入十个字符"a"。
class ThreadA extends Thread{
public List list = new ArrayList();
@Override
public void run() {
for (int i=0;i<10;i++){
list.add("a");
}
}
}
主函数中定义两个线程,使他们分别执行类ThreadA中的run()方法,他们会在两个数组中分别存入十个字符"a"。
public static void main(String[] args) {
ThreadA a=new ThreadA();
ThreadA b=new ThreadA();
a.start();
b.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(a.list);
System.out.println(a.list);
}
3.对两次线程对同一对象进行操作:
先创建一个类RunA,这个类实现了Runnable接口,重写run()方法
class RunA implements Runnable{
public List list = new ArrayList();
@Override
public void run() {
for (int i=0;i<10;i++){
list.add("a");
}
}
}
在主函数中创建一个对象 run,创建两个线程,两个线程对象都指向run对象,会对run执行两次
public static void main(String[] args) {
RunA run = new RunA();
Thread a = new Thread(run);
Thread b = new Thread(run);
a.start();
b.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(run.list);
System.out.println(run.list.size());
}
结果如下:
4.锁对象
锁对象 Lock
Lock lock = new ReentrantLock();//创建锁对象
可以在ReentrantLock()的括号中传入参数,传入参数true这个锁对象就是公平锁,不传入参数或传入false,这个锁就是非公平锁
Lock lock1 = new ReentrantLock(true);//创建公平锁
Lock lock2 = new ReentrantLock(false);//创建非公平锁(默认状态下是非公平锁)
有两个方法:
lock() 加锁
lock.trylock() 尝试加锁,是布尔类型,加锁成功返回true,失败返回false
public void method(){
if (lock.tryLock()) {
System.out.println(Thread.currentThread().getName() + "进入方法");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "结束方法");
lock.unlock();
}else {
System.out.println("加锁未成功----去执行别的代码");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
method();
}
}
public static void main(String[] args) {
Runnable run = new EasyThreadB()::method;
Thread a = new Thread(run);
Thread b = new Thread(run);
a.start();
b.start();
}
5.ReentrantLock中的两把锁
读锁和写锁是在锁盒子(ReentranReadWriteLock)中的两把锁
public static ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();
public static ReentrantLock rl = new ReentrantLock();
读锁:
ReentrantLock对象的readLock()方法
public static void main(String[] args) {
Runnable run = EasyThreadC::method;
Runnable runWrite = EasyThreadC::methodWrite;
Thread a = new Thread(run);
a.start();
Thread b = new Thread(run);
b.start();
Thread c = new Thread(run);
c.start();
Thread d = new Thread(run);
d.start();
Thread e = new Thread(run);
e.start();
}
public static void method(){
System.out.println(Thread.currentThread().getName()+"进入方法");
Lock lock = rrwl.readLock();
lock.lock();
System.out.println(Thread.currentThread().getName()+"加锁成功----读锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
lock.unlock();
System.out.println(Thread.currentThread().getName()+"方法结束");
}
写锁:
ReentrantLock对象的writeLock()方法
public static void methodWrite(){
System.out.println(Thread.currentThread().getName()+"进入方法");
Lock lock = rrwl.writeLock();
lock.lock();
System.out.println(Thread.currentThread().getName()+"加锁成功----写锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"方法结束");
lock.unlock();
}
public static void main(String[] args) {
Thread f = new Thread(runWrite);
f.start();
Thread g = new Thread(runWrite);
g.start();
Thread h = new Thread(runWrite);
h.start();
Thread i = new Thread(runWrite);
i.start();
System.out.println("main线程结束--------");
}
6.锁对象的方法
先创建一个锁对象:
public static final Object OBJ=new Object();//作为锁对象
OBJ.wait(); 让执行到该行代码的线程进入等待状态(等待池中等待)
OBJ.notify(); 唤醒一条被该锁对象wait的线程
OBJ.notifyAll(); 唤醒全部被该锁对象wait的线程
注意:只有锁对象才能调用这三种方法
public static void method(){
System.out.println(Thread.currentThread().getName()+"进入方法");
synchronized (OBJ){
OBJ.notify();//唤醒一条被该锁对象wait的线程
//OBJ.notifyAll();//唤醒全部被该锁对象wait的线程
System.out.println(Thread.currentThread().getName()+"进入同步代码块");
try {
try {
System.out.println(Thread.currentThread().getName()+"进入等待状态");
OBJ.wait();//只有锁对象才能调用wait方法
//让执行到该行代码的线程进入等待状态(等待池中等待)
System.out.println(Thread.currentThread().getName()+"重新运行");
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"结束同步代码块");
OBJ.notify();
}
}
public static void main(String[] args) {
Runnable run = EasyThreadD::method;
Thread a = new Thread(run);
a.start();
Thread b = new Thread(run);
b.start();
Thread c = new Thread(run);
c.start();
Thread d = new Thread(run);
d.start();
}
wait方法和sleep方法的区别:
wait是Object中定义的方法,可以用锁对象调用,让执行到该代码的线程进入到等待状态
sleep是Thread类中定义的静态方法,也可以让执行到该行的线程进入等待状态
区别:
1.sleep需要传入一个时间(毫秒数),到达时间后会自动唤醒
wait不能自动唤醒,必须调用notify方法或notifyAll方法唤醒
2.sleep方法保持锁状态进入等待状态,其他线程不可运行
wait方法被锁对象解除锁状态,其他线程可以介入运行
7.线程池
池的作用:重用
线程池的作用:对线程进行创建和管理,以及销毁线程
创建一个线程池对象:
ThreadPoolExecutor tpe = new ThreadPoolExecutor(,,,,,,);
//括号中要传入7个参数
要传入的参数:
这七个参数的含义分别为:
开启线程池:
tpe.execute(run);
关闭线程池:
注意:线程池像输入输出流一样,开启后需要关闭!!!
tpe.shutdown();//结束线程池
8.线程任务:
Runnable和Callable
public class EasyExecuters {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ArrayBlockingQueue qu = new ArrayBlockingQueue(12);//队列里只能放12个任务
ThreadPoolExecutor tpe = new ThreadPoolExecutor(5,//核心线程数
10,//最大线程数
10,//存活时间
TimeUnit.SECONDS,//时间类型
qu,//工作队列
Executors.defaultThreadFactory(),//工厂
new ThreadPoolExecutor.AbortPolicy());//回绝策略
Runnable run = EasyExecuters::method;
tpe.execute(run);
Callable<String> call = EasyExecuters::methodCall;
Future<String> f = tpe.submit(call);
//tpe.submit(run);
System.out.println(f.get());//会等待线程执行完毕
tpe.shutdown();//结束线程池
}
public static void method(){
System.out.println(Thread.currentThread().getName()+"执行代码");
}
public static String methodCall() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"执行代码");
Thread.sleep(2000);
return "callResult";
}
}
9.回绝策略:
回绝策略分为四个 :
1.AbortPolicy(默认的回绝策略)放弃该任务并且会抛出一个异常RejectdExecutionException,只有AbortPolicy回绝策略会抛出异常
2.CallerRunsPolicy 调用者执行,让传递任务的线程执行此任务,不抛出异常
3.DiscardOldestPolicy 放弃队列中时间最长的任务,将新任务加到队列中,不会抛出异常
4.DiscardPolicy 直接放弃新任务,不会抛出异常
10.线程池的工作原理
<1>池中是否有空闲的线程,如果有就让线程执行任务
<2>当工作队列填满后,如果没有空闲的线程,判断池中的线程数量有没有达到核心线程数
<3>如果没有达到核心线程数,会创建新的线程执行新的任务,直到填满核心线程数。如果已经达到,优先在队列中存储,直到队列填满
<4>工作队列填满之后再添加新的任务,判断是否达到最大线程数,如果没有,创建新的线程执行任务直到填满最大的线程数
<5>已经填满最大线程数,队列也已经填满,没有空闲的线程,就执行回绝策略
11.核心线程数注意点:
1.线程池中的线程达到/超过核心线程数,超出的数量会根据存活时间,进行销毁,直到数量达到核心线程数
2.如果线程的数量少于核心线程数,不会消亡
12.Java中内置的线程池对象:
可以根据工作任务来创建线程,如果没有空闲的线程,就创建新的线程
注意:线程存活时间:60s
Executors.newCachedThreadPool();
Executors.newFixedThreadPool(10);设定最大线程数量的线程池
Executors.newScheduledThreadPool(10);提供定时运行的处理方案(可以延期运行)
Executors.newSingleThreadExecutor();创建一个单个线程的线程池 保障任务队列完全按照顺序执行
public class EasyExecutersA {
public static void main(String[] args) {
BlockingQueue queue = new ArrayBlockingQueue(12);
ThreadPoolExecutor tpe = new ThreadPoolExecutor(
5,8,10, TimeUnit.SECONDS,queue,
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()
);
Runnable run = ()->{
System.out.println(Thread.currentThread().getName()+"执行代码run");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"代码执行完毕");
};
for (int i=0;i<12;i++){
tpe.execute(run);
}
tpe.shutdown();
}
}
13.synchronized和Lock 的实例
Lock:
public class EasyThreadE {
public static void main(String[] args) {
EasyList list=new EasyList();
Runnable runSize=()->{list.size();};
Runnable runGet=()->{list.get(0);};
Runnable runAdd=()->{list.add(12);};
list.add(12);
Thread a=new Thread(runSize);
Thread b=new Thread(runGet);
Thread c=new Thread(runAdd);
a.start();b.start();c.start();
}
}
class EasyList{
private int[] values=new int[20];
private int size=0;
ReentrantReadWriteLock rwLock=new ReentrantReadWriteLock();
public int size(){
Lock readLock=rwLock.readLock();
readLock.lock();
System.out.println(Thread.currentThread().getName()+"Size开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"Size结束");
readLock.unlock();
return size;
}
public int get(int index){
Lock readLock=rwLock.readLock();
readLock.lock();
System.out.println(Thread.currentThread().getName()+"Get开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(index>=size){
throw new IndexOutOfBoundsException("index is "+index);
}
System.out.println(Thread.currentThread().getName()+"Get结束");
readLock.unlock();
return values[index];
}
public boolean add(int item){
Lock writeLock=rwLock.writeLock();
writeLock.lock();
System.out.println(Thread.currentThread().getName()+"Add开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(size>=values.length){
return false;
}
values[size++]=item;
System.out.println(Thread.currentThread().getName()+"Add结束");
writeLock.unlock();
return true;
}
}
synchronized锁:
public class EasyThreadE {
public static void main(String[] args) {
EasyList list=new EasyList();
Runnable runSize=()->{list.size();};
Runnable runGet=()->{list.get(0);};
Runnable runAdd=()->{list.add(12);};
list.add(12);
Thread a=new Thread(runSize);
Thread b=new Thread(runGet);
Thread c=new Thread(runAdd);
a.start();b.start();c.start();
}
}
class EasyList{
private int[] values=new int[20];
private int size=0;
ReentrantReadWriteLock rwLock=new ReentrantReadWriteLock();
public synchronized int size(){
System.out.println(Thread.currentThread().getName()+"Size开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"Size结束");
return size;
}
public synchronized int get(int index){
System.out.println(Thread.currentThread().getName()+"Get开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(index>=size){
throw new IndexOutOfBoundsException("index is "+index);
}
System.out.println(Thread.currentThread().getName()+"Get结束");
return values[index];
}
public synchronized boolean add(int item){
System.out.println(Thread.currentThread().getName()+"Add开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(size>=values.length){
return false;
}
values[size++]=item;
System.out.println(Thread.currentThread().getName()+"Add结束");
return true;
}
}