Java中线程入门

多线程入门

入门案例

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();

   }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值