一、线程三种创建方式
1、Thread class :继承Thread类
2、Runnable接口:实现Runnable接口
3、Callable接口:实现Callable接口
二、创建线程方式一:继承Thread类
1、自定义线程类继承Thread类,重写run()方法,编写线程执行体,创建线程对象,调用start()方法启动线程。
2、总结:线程开启不一定立即执行,需cpu调用。
3、示例:
public class MyThread extends Thread{ @override public void run(){ 方法体; } public static void main(String [] args){ MyThread myThread = new MyThread(); myThread.start(); } }
注:不建议使用继承Thread类,避免OOP单继承的局限性。
三、创建线程方式二:实现Runnable接口
1、定义MyRunnable类实现Runnable接口,实现run()方法,编写线程执行体,创建线程对象,调用start()方法启动线程。
2、示例:
public class MyThread implements Runnable{ @override public void run(){ 方法体; } public static void main(String [] args){ MyThread myThread = new MyThread(); //创建三个线程t1、t2、t3 Thread t1 = new Thread(myThread); Thread t2 = new Thread(myThread); Thread t3 = new Thread(myThread); //执行t1、t2、t3三个线程 t1.start(); t2.start(); t3.start(); } }
注:推荐使用实现Runnable接口方式,因为避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用。
四、创建线程方式三:实现Callable接口
1、实现Callable接口,需要返回值类型
2、重写call方法,需要抛出异常
3、创建目标对象
4、创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
5、提交执行:Future <Boolean> result = ser.submit(1);
6、获取结果:boolean flag = result.get();
7、关闭服务:ser.shutdownNow();
8、示例:
public class MyThread implements Callable<Boolean>{ @override public Boolean call(){ 方法体; } public static void main(String [] args){ MyThread myThread = new MyThread(); //创建三个线程t1、t2、t3 Thread t1 = new Thread(myThread); Thread t2 = new Thread(myThread); Thread t3 = new Thread(myThread); //创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(3); //提价三个执行 Futurn<Boolean> r1 = ser.submit(t1); Futurn<Boolean> r2 = ser.submit(t2); Futurn<Boolean> r3 = ser.submit(t3); //获取三个执行结果 boolean rs1 = r1.get(); boolean rs1 = r1.get(); boolean rs1 = r1.get(); //关闭服务 ser.shutdownNow(); } }
五、静态代理模式总结
1、真实对象和代理对象都要是实现同一个接口
2、代理对象要代理真是角色
3、好处:代理对象可以做很多真是对象做不了的事情,真实对象专注做自己的事情
六、Lambda表达式
1、函数式接口:接口里面只有一个方法。
2、示例:
//lambda表示简化 Ilove love = (int a)->{ System.out.printIn("i love you-->" + a); }; //简化1:参数类型,多个参数也可以去掉参数类型,要去掉就都去掉,不过必须加上括号 love = (a)->{ System.out.printIn("i love you-->" + a); }; //简化2:简化括号,针对于一个参数 love = a->{ System.out.printIn("i love you-->" + a); }; //简化3:去掉花括号,只有一行代码时才能去掉花括号,如果有多行,则需用花括号(代码块)包裹起来 love = a->System.out.printIn("i love you-->" + a);
注:使用Lambda表达式前提是接口必须为函数式接口。
七、线程状态
1、五大状态:
2、图解详细分析
八、线程方法
1、线程休眠(sleep(时间)):指定当前线程阻塞的毫秒数;1000ms=1s。
sleep存在异常InterruptedException;
sleep时间达到后线程进入就绪状态;
sleep可以模拟网络延时、倒计时等;
每一个对象都有一个锁,sleep不会释放锁。
2、线程礼让(yield()):礼让线程,让当前正在执行的线程暂停,但不阻塞,将线程从运行状态转为就绪状态,让cpu重新调度,礼让不一定成功,看cpu心情。
3、线程强制执行:等待该线程执行完成后,再执行其他线程,导致其他线程阻塞。
九、线程状态观测
1、Thread.State的枚举值:
-
-
NEW
尚未启动的线程处于此状态。 -
RUNNABLE
在Java虚拟机中执行的线程处于此状态。 -
BLOCKED
被阻塞等待监视器锁定的线程处于此状态。 -
WAITING
正在等待另一个线程执行特定动作的线程处于此状态。 -
TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 -
TERMINATED
已退出的线程处于此状态。
-
十、线程优先级
1、范围从1~10,默认为5,Thread.MIN_PRIORITY = 1;Thread.MAX_PRIORITY = 10;Thread.NORM_PRIORITY = 5;先设置线程优先级,再启动线程。
十一、守护线程(比如:GC(JVM中的垃圾回收机制))
1、线程分为用户线程和守护线程。
2、虚拟机必须确保用户线程执行完毕,而不用等待守护线程执行完毕。
3、守护线程:后台记录操作日志、监控内存、垃圾回收等待。
4、thread.setDaemon(true);//默认是false表示用户线程,true为守护线程
十二、线程同步机制
1、概念:一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。
2、并发:多个线程访问同一个对象。
3、线程同步的安全性的形成条件:队列+锁
4、锁机制实现线程同步,用synchronized关键字(隐式锁)
5、同步方法:在修饰方法中synchronized关键字进行修饰。
同步方法缺点:若将一个打的方法申明为synchronized,将会影响效率。
解决方法:将方法里需要修改的内容才需要加锁,锁太多,浪费资源。
6、同步块:synchronized(Obj obj){}
Obj称为同步监视器,可以是任何对象,但推荐使用共享资源作为同步监视器。
同步方法无需指定同步监视器,因为同步方法的同步监视器就是this,即这个对象本身或者是class。
十三、JUC(并发编程)
1、CopyOnWriteArrayList是JUC安全类型的集合
十四、死锁
1、概念:多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有"两个以上对象的锁"时,就可能会发生"死锁"的问题。
2、产生死锁的四个必要条件:
a、互斥条件:一个资源每次只能被一个进程使用。
b、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
c、不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
d、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
3、避免死锁方法:破以上四个必要条件的一个或多个条件即可。
十五、Lock(锁)
1、是显示定义锁,是显示加锁
2、示例
//定义lock锁 private final ReentrantLock lock = new ReentrantLock(); //加锁 try{ lock.lock(); //被加锁的执行代码 }finally{ //解锁 lock.unlock(); }
3、synchronized与Lock的对比
a、Lock是显示锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放。
b、Lock只有代码块锁,synchronized有代码块锁和方法锁
c、使用Lock锁,JVM将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)
d、优先使用顺序:Lock>同步代码块>同步方法
十六、线程通信:
1、方法:
wait():线程一直等待,直到其他线程通知,与sleep不同,会释放锁。
wait(long timeout):指定等待的毫秒数
notify():唤醒一个处于等待状态的线程
notifyAll():唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度。
2、生产者消费者模型的两个方法:管程法、信号灯法
注:均是Object类的方法,都只能在同步方法或同步代码块中使用,否则会抛出异常lllegalMonitorStateException。
十七、线程池
1、ExecutorService:真正的线程池接口,常见子类:ThreadPoolExecutor。
2、void execute(Runnable command):执行任务命令,没有返回值,一般用于执行Runnable。
3、<T> Futurn<T>submit(Callable<T>task):执行任务,有返回值,一般用于执行Callable
4、void shutdown():关闭连接池。
5、Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池。
6、示例:
//创建服务,创建线程池 ExecutorService service = Executors.newFixedThreadPool(10); //执行 service.execute(new MyThread()); service.execute(new MyThread()); ...... //关闭连接 service.shutdown();