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();@Overridepublic 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();@Overridepublic 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;}
}