Thread 线程创建
-
extends Thread (继承线程类)
-
class Demo extends Thread { public void run (){ //运行主体 } public static void main (String[] args){ new Demo.start(); } }
-
优点:敏捷,不需要代理类运行
-
缺点:类只能单一继承,会占用继承
-
-
implements Runnable (实现接口)
-
class Demo implements Runnable { public void run (){ //运行主体 } public static void main (String[] args){ Thread thread = new Thread(new Demo()); thread.start(); } }
-
优点:不占用继承
-
缺点:需要代理类包装
-
-
implements Callable(实现接口)
-
class Demo implements Callable { public Boolean call (){ //运行主体 return true; } public static void main (String[] args) throws ExecutionException,InterruptedException { //创建执行服务 ExecutorService ser = Executors.new FixedThreadPool(1); //提交线程 Future<Boolean> result = ser.sumbit(new Demo()); //获取结果 Boolean b = result.get(); //关闭服务 ser.shutdownNow(); } }
-
功能:带返回值,会抛出异常
-
Thread 线程状态
- 五种基础状态
- 新建状态
- 可运行状态
- 运行状态
- 阻塞状态
- 死亡状态
Thread 线程状态切换方法
守护线程 (Daemon)
-
虚拟机内运行的线程都死亡,守护线程会最后再死亡,无论线程内部是否是死循环
-
Thread thread = new Thread(); //设置该线程为守护线程 thread.setDaemon(true);
Thread 同步(Synchronized)
-
目的:为了解决线程不安全的问题
-
方法:
-
方法添加 synchronized 修饰符
-
public synchronized void run (){}
-
该同步会锁定方法所在的类或class,this对象
-
-
代码块添加 synchronized 修饰符
-
public void run (){ synchronized(需要锁定的对象){ //代码块实现 } }
-
-
Lock 锁 (reentrantlock 可重入锁定)
-
目的:跟同步一样,也是为了解决线程不安全的问题,不过比起同步的解决办法,Lock锁性能损耗更小,使用更灵活
-
ReentrantLock lock = new ReentrantLock(); //在加锁解锁之间的代码,被锁定操作 try { //加锁 lock.lock(); } catch (Exception e){ //捕获异常 } finally { //解锁 lock.unlock(); }
-
死锁
- 简而言之,某个代码块同时拥有”两个以上对象的锁“时,就可能发生死锁的问题
- 造成死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
线程通信方法
-
理解:线程与线程之间,为了达成之间运行的条件,需要与另一个线程进行通信处理
- 如:生产者与消费者案例,生产多少消费多少
-
解决方法
-
管程法(利用容器作为条件)
-
信号灯法(利用布尔值作为条件)
//定义一个容器 ,用数组或者集合实现都可以 Int[] array = new Int[10]; //定义一个信号灯 Boolean flag = false; public synchronized void run (){ //满足条件就等待 以上方法二选一作为条件判断 if(flag){ //wait方法会释放锁,等待的线程会回到锁池状态 this.wait(); } //不满足就唤醒其余所有线程 this.notifyAll(); }
-
线程池
-
背景:经常创建和销毁线程、使用量特别大的资源,比如并发的情况下的线程,对性能影响很大 (线程一旦死亡,不能再启动)
-
思路:提前创建好多个线程,放入线程池,使用时直接获取,使用完放回池中,避免了频繁创建销毁,实现重复利用
-
用法:使用 ExecutorService 工具类创建
-
ExecutorService ser = new FixedThreadPool(4); //执行线程 ser.execute(new Thread()); ser.execute(new Thread()); ser.execute(new Thread()); ser.execute(new Thread()); //关闭服务 ser.shutdown();
-