黑马程序员——Java 基础:多线程

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

一、概述
  在一个程序里可以在运行时创建多个线程,以达到同时处理数据,提高整体的运行效率的目的。

二、创建线程
  在 Java 语言中,创建线程有两种方式,第一种是创建一个类,让其继承 Thread 类,并重写 run 方法,在其中写入要执行的语句:

// 创建一个类,让其继承 Thread 类
class Demo extends Thread {
    public void run () {
        while(true){
            System.out.println("线程");
        }
    }
}
// 在主函数中创建该类的对象并启动线程
class ThreadDemo {
    public static void main (String[] args) {
        Demo d = new Demo();
        d.start();
    }
}

  因为 Demo 类继承了 Thread 类,因此可以使用 start 方法启动线程并执行 run 方法中的语句。
第二种创建线程的方法是创建一个类,让其实现 Runable 接口,并在类中重写 run 方法,在其中写入要执行的语句:

// 创建一个类,让其实现 Runable 接口
class Demo implements Runable {
    public void run () {
        while (true) {
            System.out.println("线程");
        }
    }
}
// 在主函数中创建该类的对象,并使用该对象创建线程
class ThreadDemo {
    public static void main (String[] args) {
        Demo d = new Demo();
        Thread t = new Thread(d);
        t.start();
    }
}

  使用第二种方法创建线程可以将一个对象传递给多个线程,从而实现类中数据的共享。

三、线程的状态
  线程的状态可以分为被创建、运行、冻结、和消亡状态,线程通过创建 Thread 类对象被创建,通过 start 方法开始运行,通过 sleep 或 wait 方法进入冻结状态,在进过 sleep 方法设置的时间后,或是被 notify 方法唤醒后恢复运行运行状态,run 方法中的语句执行完毕后或通过 stop 方法(此方法在较新的 Java 版本中已过期)结束运行。

四、多线程的安全性
  当 run 方法中存在多条语句,则可能存在某个线程在执行到某一条语句之后失去 CPU 的执行权,转到另一个线程执行 run 方法中的语句的情况,最终导致执行的结果出现问题。

// 定义一个类继承 Thread 类,在 run 方法定义循环,要求在成员变量 a 大于 0 时打印 a 的值
class Demo implements Runable {
    int a = 100;
    public void run () {
        while (true) {
            if (a > 0) {
                System.out.println(a);
                a--;
            }
        }
    }
}
// 在主函数中创建并启动两个线程执行 run 方法中语句
class ThreadDemo {
    public static void main (String[] args) {
        Demo d = new Demo();
        Thread t1 = new Thread(d);
        Thread t2 = new Thread(d);
        t1.start();
        t2.start();
    }
}

  在上面的代码中,有可能出现在 a 变量变为 1 时,t1 线程在执行了 if (a>0) 判断语句之后失去了 CPU 的执行权,然后 t2 线程获得了 CPU 的执行权,此时 a 值为 1,t2 线程线程执行打印语句,a 的值减为 0,此时 t1 线程重新或的执行权,由于已经执行的判断语句,t1 线程会直接执行打印语句,并打印出 0 值,这不符合最初的设计要求。
  为了解决线程的安全性问题,需要在执行语句中加入 Synchronized 代码块或用 Synchronized 修饰方法,上面的代码在引入同步之后可以改写为:

class Demo implements Runable {
    int a = 100;
    public void run () {
        while (true) {
             // 使用同步代码块
            Synchronized (this) 
            {
                if (a > 0) {
                    System.out.println(a);
                    a--;
                }
            }
        }
    }
}

  使用同步代码块需要有一个对象,这里使用调用函数的对象 this。

class Demo implements Runable {
    int a = 100;

    public void run () {
        while (true) {
            out();
        }
    }
    // 定义同步方法
    public Synchronized void out() {
        if (a > 0) {
            System.out.println(a);
            a--;
        }
    }
}

  在使用了同步代码块或同步方法后,在一个线程开始执行代码块中或方法中的语句后,该线程执行完毕前,其他进程既不能执行该段代码或该方法,从而解决了线程的安全问题。

五、使用 Lock 接口实现同步
  在 JDK 5.0 中引入新的 Lock 接口,使用 Lock 接口同样可以实现同步,解决多线程的安全性问题。上面的代码可以改写为:

// 在类中创建 Lock 接口的子类对象,并使用 Lock 中的方法实现同步
class Demo implements Runable {
    int a = 100;
    private Lock lock = new ReentrantLock();
    public void run () {
        while (true) {
            lock.lock();
            if (a > 0) {
                System.out.println(a);
                a--;
            }
            lock.unlock();
        }
    }
}

  Lock 接口使用两个不同的方法获取和释放锁,此外,还支持多个 Condition 对象,可以实现更为灵活的线程控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值