线程的创建和销毁很耗费计算机的资源,由此衍生出了线程池的概念!
线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源!
//线程放在线程池中,用的时候拿出来使用,不用的时候放回池子中!
强调:多线程很重要,线程池主要用来解决线程生命周期开销问题和资源不足问题!
实现线程池的两种方式:
实现Runnable接口:缺点无返回值,不可以throws抛出异常!
实现Callable接口:有返回值,可以throws抛出异常!
示例代码(重要):
package com.oracle.duoxiancheng20180827; //实现Runnable接口,重写run方法: public class MyRunnable implements Runnable { //无返回值,不可以抛异常: public void run(){ for(int i=0;i<50;++i){ System.out.println("Run……"+i); } } } package com.oracle.duoxiancheng20180827; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo01 { public static void main(String[] args) { //获取线程池对象(从线程池工厂中获得): ExecutorService es=Executors.newFixedThreadPool(2); //创建Runnable接口子类对象: MyRunnable mr=new MyRunnable(); //提交Runnable子类对象(线程池自动选一条线程执行提交上来的任务): es.submit(mr); //在Main方法中写一个for循环,试验有没有多线程: for(int i=0;i<50;++i){ System.out.println("Main……"+i); } //以上代码走完run方法该线程就灭了,但是该线程在线程池中,除非shutdown该线程池,不然该线程是不死的! //没有线程池之后,程序执行网run()方法,该线程就被Terminated,有了线程池之后,线程执行完会归还到线程池中,调用线程池的shutdown()方法关闭线程池,该线程才会关闭! //关闭线程池: es.shutdown(); //关闭线程池之后,看到执行过后terminate已经灭了! //线程池内线程数量尽量开的大一点,不然多余线程会等前面线程结束之后再加入运行! } } package com.oracle.duoxiancheng20180827; import java.util.concurrent.Callable; //Callable泛型就是Call方法的返回值类型! public class MyCallable implements Callable<String> { public String call() throws Exception { return "这是Call方法!"; } } package com.oracle.duoxiancheng20180827; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo02 { public static void main(String[] args) throws InterruptedException, ExecutionException { //Callable专用于线程池,有返回值,可以throws抛出异常! //获取线程池: ExecutorService es=Executors.newFixedThreadPool(2); //创建Callable子类: MyCallable mc=new MyCallable(); //提交Callable子类: Future<String> fu=es.submit(mc); //默认调用toString方法,打印出地址! System.out.println(fu); //调用Future对象fu的.get()方法,打印出mc的返回值: System.out.println(fu.get()); //关闭线程池: es.shutdown(); } } package com.oracle.duoxiancheng20180827; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo03 { public static void main(String[] args) throws InterruptedException, ExecutionException { //异步计算0-100,0-200的和: //通过线程工厂获取线程池: ExecutorService es=Executors.newFixedThreadPool(2); //创建Callable对象,并传参: YBJSCallable yc1=new YBJSCallable(100); YBJSCallable yc2=new YBJSCallable(200); //扔进线程池: Future<Integer> fu1=es.submit(yc1); Future<Integer> fu2=es.submit(yc2); //打印返回结果: System.out.println(fu1.get()); System.out.println(fu2.get()); } } package com.oracle.duoxiancheng20180827; import java.util.concurrent.Callable; //异步计算Callable类: public class YBJSCallable implements Callable<Integer> { private Integer getNum; //通过构造方法传参: YBJSCallable(Integer getNum){ this.getNum=getNum; } //Call方法无法传参: public Integer call() throws Exception { int sum=0; for(int i=0;i<=getNum;++i){ sum+=i; } return sum; } //由于Callable的call()方法无法传参,所以声明一个修饰符为private的成员变量,再写一个构造方法,用于传参! } package com.oracle.duoxiancheng20180827; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo03 { public static void main(String[] args) throws InterruptedException, ExecutionException { //异步计算0-100,0-200的和: //通过线程工厂获取线程池: ExecutorService es=Executors.newFixedThreadPool(2); //创建Callable对象,并传参: YBJSCallable yc1=new YBJSCallable(100); YBJSCallable yc2=new YBJSCallable(200); //扔进线程池: Future<Integer> fu1=es.submit(yc1); Future<Integer> fu2=es.submit(yc2); //打印返回结果: System.out.println(fu1.get()); System.out.println(fu2.get()); } } package com.oracle.homework; import java.util.concurrent.Callable; //计算两个数相加: public class PlusCallable implements Callable { //定义接收两个数的私有成员变量: private Integer firNum; private Integer secNum; //定义构造方法用于传参: public PlusCallable(Integer firNum, Integer secNum) { super(); this.firNum = firNum; this.secNum = secNum; } //GET+SET方法: public Integer getFirNum() { return firNum; } public void setFirNum(Integer firNum) { this.firNum = firNum; } public Integer getSecNum() { return secNum; } public void setSecNum(Integer secNum) { this.secNum = secNum; } //重写call()方法: public Object call() throws Exception { return firNum+secNum; } } package com.oracle.homework; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TestPlusCall { public static void main(String[] args) throws InterruptedException, ExecutionException { //从线程池工厂获取线程池对象: ExecutorService es=Executors.newFixedThreadPool(1); //创建线程任务并传参: PlusCallable pc1=new PlusCallable(23,56); PlusCallable pc2=new PlusCallable(66,99); //Future对象获取返回值: //执行完第一个线程,扔回线程池里,接着执行第二个,通过一个线程运算的两个结果! Future<Integer> fu1=es.submit(pc1); Future<Integer> fu2=es.submit(pc2); //打印结果: System.out.println(fu1.get()); System.out.println(fu2.get()); //关闭线程池: es.shutdown(); } }
死锁演示:
package com.oracle.tickets; public class LockA { private LockA(){ } public final static LockA LockA=new LockA(); } package com.oracle.tickets; public class LockB { private LockB(){ } public final static LockB LockB=new LockB(); } package com.oracle.tickets; public class DeadLock implements Runnable { private int i=0; public void run() { while(true){ if(i%2==0){ synchronized(LockA.LockA){ System.out.println("if……LockA"); synchronized(LockB.LockB){ System.out.println("if……LockB"); } } }else{ synchronized(LockB.LockB){ System.out.println("else……LockB"); synchronized(LockA.LockA){ System.out.println("else……LockA"); } } } ++i; } } } package com.oracle.tickets; public class Demo03 { public static void main(String[] args) { DeadLock DeadLock=new DeadLock(); Thread th1=new Thread(DeadLock); Thread th2=new Thread(DeadLock); th1.start(); th2.start(); } } package com.oracle.tickets; public class SafeTicket implements Runnable { private static int ticNum=100; private Object obj=new Object(); public void run(){ while(true){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(obj){ if(ticNum>0){ System.out.println(Thread.currentThread().getName()+"出售第"+ticNum--+"张票!"); } } } } public void run(){ while(true){ sale(); } } //是new SafeTicket()对象,this关键字! public static synchronized void sale(){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } if(ticNum>0){ System.out.println(Thread.currentThread().getName()+"出售第"+ticNum--+"张票!"); } } } package com.oracle.tickets; public class Demo03 { public static void main(String[] args) { DeadLock DeadLock=new DeadLock(); Thread th1=new Thread(DeadLock); Thread th2=new Thread(DeadLock); th1.start(); th2.start(); } } package com.oracle.tickets; public class Demo01 { public static void main(String[] args) { SafeTicket th=new SafeTicket(); Thread t1=new Thread(th); Thread t2=new Thread(th); Thread t3=new Thread(th); t1.start(); t2.start(); t3.start(); } } package com.oracle.tickets; public class Demo02 { public static void main(String[] args) { NewTickets th=new NewTickets(); Thread t1=new Thread(th); Thread t2=new Thread(th); Thread t3=new Thread(th); t1.start(); t2.start(); t3.start(); } }
线程同步锁:
① Synchronized
② Lock接口
同步代码块: 在代码块声明加上synchronized!
synchronized (锁对象) {
可能会产生线程安全问题的代码!
}
同步代码块中的锁对象可以是任意的对象,但多个线程时,要使用同一个锁对象才能够保证线程安全!
对象锁,同步锁,对象监视器-->都是同步锁!
同步怎么保证安全性?同步中有锁,没有锁的线程不能执行,只能等!
同步方法:在方法声明上加上synchronized!
public synchronized void method(){
可能会产生线程安全问题的代码!
}
同步方法中的锁对象是this,即new Tickets()对象!
静态同步方法: 在方法声明上加上static synchronized!
public static synchronized void method(){
可能会产生线程安全问题的代码!
}
静态同步方法中的锁对象是本类字节码对象类名.class!
StringBuilder和StringBuffer区别:
StringBuilder速度快安全性差
StringBuffer速度慢安全性高-->带同步锁,多线程时要等锁回来!
//多线程共享同一个数据会出现线程安全问题!
线程中出现多个同步锁时,如果同步锁中出现了其他的同步锁;容易引发程序的无限等待,这种现象我们称为死锁!
Lock接口:
Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能!