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 = new Thread(); //设置该线程为守护线程 thread.setDaemon(true);
目的:为了解决线程不安全的问题
方法:
方法添加 synchronized 修饰符
public synchronized void run (){}
该同步会锁定方法所在的类或class,this对象
代码块添加 synchronized 修饰符
public void run (){ synchronized(需要锁定的对象){ //代码块实现 } }
目的:跟同步一样,也是为了解决线程不安全的问题,不过比起同步的解决办法,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();