子类继承Thread类具备多线程能力
启动线程:子类对象.start()
不建议是使用:避免oop单继承局限性
TestThread testThread = new TestThread(); testThread.start();实现接口runnable具有多线程能力
启动线程:传入目标对象+Thread对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
TestThread1 t1 = new TestThread1(); //Thread thread = new Thread(t1); //thread.start(); new Thread(t1).start();好处:
代理对象可以做很多真实对象做不了的事情真实对象专注做自己的事情 public class StaticProxy { public static void main(String[] args) { you you = new you();//你要结婚 new Thread( ()-> System.out.println("我爱你")).start(); new WeddingCompany(new you()).HappyMarry(); /*WeddingCompany weddingCompany = new WeddingCompany(you); weddingCompany.HappyMarry();*/ } } interface Marry{ void HappyMarry(); } //真实角色,你去结婚 class you implements Marry{ @Override public void HappyMarry() { System.out.println("我要结婚了,很开心"); } } //代理角色,帮助你结婚 class WeddingCompany implements Marry{ private Marry target; WeddingCompany(Marry target){ this.target = target; } @Override public void HappyMarry() { before(); this.target.HappyMarry(); after(); } private void after() { System.out.println("结婚之后,收取尾款"); } private void before() { System.out.println("结婚之前,布置现场"); } }理解Functional Interface(函数式接口)是学习java8 lambda表达式的关键所在
函数式接口的定义:
任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
//退到lambda表达式 public class TestLambda1 { //3.静态内部类 static class Like2 implements ILike{ @Override public void lambda() { System.out.println("i like lambda2"); } } public static void main(String[] args) { ILike like = new Like(); like.lambda(); like = new Like2(); like.lambda(); //4.局部内部类 class Like3 implements ILike{ @Override public void lambda() { System.out.println("i like lambda3"); } } like = new Like3(); like.lambda(); //5.匿名内部类,没有类别的名称,必须借助接口或者父类 like = new ILike() { @Override public void lambda() { System.out.println("i like lambda4"); } }; like.lambda(); //6.用lambda简化 like = ()->{ System.out.println("i like lambda5"); }; like.lambda(); } } //1.定义一个函数式接口 interface ILike{ void lambda(); } //2.实现类 class Like implements ILike{ @Override public void lambda() { System.out.println("i like lambda"); } }其中,lambda可以简化
//lambda表示简化 ILove love = (int a)->{ System.out.println("i like lambda"+a); } //简化1.参数类型 ILove love = (a)->{ System.out.println("i like lambda"+a); } //简化2.简化括号 ILove love = a ->{ System.out.println("i like lambda"+a); } //简化3.去掉花括号 ILove love = a -> System.out.println("i like lambda"+a);总结:
lambda表达式只能有一行代码的情况下才能简化成一行,如果有多行,那么就用代码块包裹(花括号)前提必须是函数式接口多个参数也可以去掉参数类型,要去就都去掉,必须加上括号倒计时的例子
public class Sleep { public static void main(String[] args) throws InterruptedException { tenDown(); } public static void tenDown() throws InterruptedException { int num = 10; while (true){ Thread.sleep(1000); System.out.println(num--); if (num<=0){ break; } } } }动态刷新当前的系统时间
public class Sleep { public static void main(String[] args) { //打印当前系统时间 Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间 while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis());//更新当前时间 } } }java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
线程的优先级用数字表示,范围从1~10
Thread.MIN_PRIORITY = 1;Thread.MAX_PRIORITY = 10;Thread.NORM_PRIORITY = 5;使用以下方式改变或获取优先级
getPriority().setPriority(int xxx)优先级的设定建议在start()调度前
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看cpu的调度
同一个对象 被 多个线程同时操作
处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象.这时候我们就需要线程同步,线程同步其实就是一种 等待机制,多个需要同时访问此对象的线程进入这个 对象的等待池形成队列,等待前面线程使用完毕,下个线程再使用
形成条件:队列+锁保证安全性
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突的问题,为了保证数据在方法中被访问的正确性,在访问时加入了 锁机制 synchronized,当一个线程获得对象的排它锁,独占资源其他线程必须等待,使用后释放锁即可
一个线程持有锁会导致其他所有需要此锁的线程挂起在多线程竞争下,加锁,释放锁会导致会比较多的上下文切换和调度延时,引起性能问题如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题synchronized(obj){}
obj称之为 同步监视器
obj可以为任何对象,但是推荐使用共享资源作为同步监视器
同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,默认锁住是this就是这个对象本身,或者是class
同步块可以锁任何东西
锁的东西就是变化的量,需要增删改的对象
//两个人去银行取钱,账户 public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100,"结婚基金"); Drawing me = new Drawing(account,50,"自己"); Drawing GirlFriend = new Drawing(account,100,"女朋友"); GirlFriend.start(); me.start(); } } //账户 class Account{ int money;//余额 String name;//卡名 public Account(int money,String name) { this.money = money; this.name = name; } } class Drawing extends Thread{ Account account;//账户 int drawingMoney;//需要取得钱 int NowMoney;//现在还剩的钱 public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { synchronized (account){ //判断没有钱 if (account.money - drawingMoney <0){ System.out.println(Thread.currentThread().getName()+"钱不够,取不了"); return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //卡内余额 account.money = account.money - drawingMoney; //现在手里的钱 NowMoney = NowMoney + drawingMoney; System.out.println(account.name + "余额为"+account.money); System.out.println(this.getName()+"手里的钱"+NowMoney); } } } public class UnSafeList { public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } Thread.sleep(3000); System.out.println(list.size()); } }多个线程占用一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情况.某一个同步块同时拥有**“两个以上对象的锁”**时,就可能发生"死锁"的问题
产生死锁的四个必要条件
互斥条件:一个资源每次只能被一个进程使用请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系