多线程入门
入门案例
package com.cloud.day1; /* 线程的创建方式 方式一: 1.自定义一个类,继承Thread类 2.重写Thread类的run方法,run方法编写自定义线程的任务代码 3.创建Thread子类对象,调用start方法执行线程,线程一旦开启,会自动调用run方法, 如果直接调用run方法,只是单纯调用一个方法 */ public class Demo1 extends Thread{ @Override public void run() { for(int i=0;i<100;i++){ System.out.println("自定义线程"+i); } } public static void main(String[] args) { //自定义线程 Demo1 d1=new Demo1(); d1.start(); //主线程任务 for(int i=0;i<100;i++){ System.out.println("main线程"+i); } } } |
线程生命周期
1. 当new 线程对象()的时候,线程处于创建状态
2. 线程调用start()方法时,处于可运行状态,此时的线程具备等待CPU的资格,不具备CPU的执行权
3. 程序运行时,得到CPU的执行权,也具备CPU的等待资格
4. 线程调用sleep()和wait()方法时,会进入临时阻塞状态,调用sleep休眠的线程,过了休眠期可以进入可运行状态,调用wait方法的线程,需要其他线程唤醒才可以进入可运行状态
5. 当CPU的执行权被抢夺,线程回到可运行状态
6. 线程完成任务时候处于死亡状态
线程常用的方法
方法使用案例
package com.cloud.day1; public class Demo2 extends Thread{ public Demo2(String name){ super(name); } @Override public void run() { System.out.println(this); System.out.println("当前函数调用"+Thread.currentThread()); /* for (int i = 0; i < 100; i++) { System.out.println(this.getName()+":"+i); } */ } public static void main(String[] args) throws InterruptedException { Demo2 d = new Demo2("Spring"); //System.out.println("线程的默认名字:" + d.getName());//线程的名字Thread-0 System.out.println("自定义名称:"+d.getName()); //这里休眠的是main主线程,谁调用谁休眠,d.sleep(也是主线程休眠),因为是main线程调用的 //Thread.sleep(1000); System.out.println("自定义线程的优先级"+d.getPriority());//5 System.out.println("主线程的优先级"+Thread.currentThread().getPriority()); d.setName("summer"); d.setPriority(10);//设置优先级 d.start(); } } |
run方法的异常处理
在java的异常处理中,子类方法抛出的异常只能小于等于父类抛出的异常,也就是说父类不抛出异常,子类只能用捕获异常的方式处理异常。
线程的优先级
线程的优先级是指获取CPU的概率,默认是5,数字越大,优先级越大。优先级【1-10】之间,优先级高不代表一定先执行,只是先执行的概率大。
线程模拟卖票系统
package com.cloud.day1; /* 需求:模拟3个窗口同时在售50张票。 问题1 :为什么50张票被卖出了150次? 出现的原因:因为num是非静态的,非静态的成员变量数据是在每个对象中都会维护一份数据的,三个线程对象就会有三份。 解决方案:把num票数共享出来给三个线程对象使用。使用static修饰。 问题2:出现了线程安全问题 ? 线程安全问题的解决方案:sun提供了线程同步机制让我们解决这类问题的。 java线程同步机制的方式: 方式一:同步代码块 同步代码块的格式: synchronized(锁对象){ 需要被同步的代码... } 同步代码块要注意事项: 1. 任意的一个对象都可以做为锁对象。 2. 在同步代码块中调用了sleep方法并不是释放锁对象的。 3. 只有真正存在线程安全问题的时候才使用同步代码块,否则会降低效率的。 4. 多线程操作的锁对象必须是唯一共享的。否则无效。 需求:一个银行账户5000块,两夫妻一个拿着存折,一个拿着卡,开始取钱比赛,每次只能取一千块,要求不准出现线程安全问题。
方式二:同步函数 出现线程安全问题的根本原因: 1. 存在两个或者两个以上的线程对象,而且线程之间共享着一个资源。 2. 有多个语句操作了共享资源。 */ class SaleTicket extends Thread{ static int num=50; static Object o = new Object(); public SaleTicket(String name){ super(name); } @Override public void run() { while(true){ synchronized (o) { if(num>0){ System.out.println(Thread.currentThread().getName()+"卖出"+num+"号票"); num--; } else{ System.out.println("票卖完了..."); break; } } } } } public class Demo3 { public static void main(String[] args) { SaleTicket sale1 = new SaleTicket("窗口1"); SaleTicket sale2 = new SaleTicket("窗口2"); SaleTicket sale3 = new SaleTicket("窗口3"); sale1.start(); sale2.start(); sale3.start(); } } |
同步函数解决线程安全
package com.cloud.day1; /* 进程:正在运行的应用程序,决定了内存的划分 线程:进程中的代码是线程执行的,线程是进程中的一个执行路径 多线程:一个进程可以有多个线程执行任务
多线程好处: 1.解决一个进程中可以执行多个任务的问题 2.提高资源的利用率 弊端 1.增加了CPU的负担 2.降低进程中线程执行的概率 3.出现线程安全问题 出现原因: a.存在两个或者两个以上的线程共享同一个资源 b.多线程操作共享资源的代码有多句 4.出现死锁现象
解决线程安全 1.同步代码块 synchronize("锁"){ 同步代码 } 锁对象可以是任意的对象,但是必须是唯一的,线程休眠不会释放锁对象 不存在线程安全问题,不使用同步代码块,会降低效率,锁对象必须是多线程共享的资源 2.同步函数 public synchronize void run(){ 同步代码 } a.非静态的同步函数的锁对象是this对象,如果是静态函数同步的锁,锁对象是当前函数所属类的字节码文件(class对象) */ class BankThread extends Thread{ static int count = 5000; public BankThread(String name){ super(name); } @Override public void run() { getMoney(); } //静态函数--》函数所属类字节码文件对象--》BankThread.class 具备唯一性 public static synchronized void getMoney(){ while(true){ if(count>0){ System.out.println(Thread.currentThread().getName()+"取走1000,剩余"+(count-1000)); count-=1000; } else{ System.out.println("取光了..."); break; } } } } public class Demo4 { public static void main(String[] args) { BankThread th1 = new BankThread("存折"); BankThread th2 = new BankThread("银行卡"); th1.start(); th2.start(); } } |
线程的死锁现象
package com.cloud.day1; /* 同步代码块解决线程安全问题,但是也带来了线程死锁问题 死锁现象:互相等待对方的资源 原因: 1.存在两个或者以上的线程 2.存在两个或者以上的共享资源 死锁现象只能尽量避免,不能彻底解决 */ class DeadLock extends Thread{ public DeadLock(String name){ super(name); } @Override public void run() { if("抢电源".equals(Thread.currentThread().getName())){ synchronized ("抢电源") { System.out.println("抢到电源,等待遥控"); synchronized ("抢遥控") { System.out.println("1可以开空调了..."); } } }else if("抢遥控".equals(Thread.currentThread().getName())){ synchronized ("抢遥控") { System.out.println("抢到遥控,等待电源"); synchronized ("抢电源") { System.out.println("2可以开空调了"); } } } } } public class Demo5 { public static void main(String[] args) { DeadLock dl1 = new DeadLock("抢电源"); DeadLock dl2 = new DeadLock("抢遥控"); dl1.start(); dl2.start(); } } |