多线程(1):继承Thread类和实现Runnable接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fibonacci2015/article/details/84284926

多线程的两种实现方法:

1.继承Thread类

    继承Thread类,重写run()方法。创建多线程的时候,需要创建对象实例,然后调用start()方法。类对象的属性属于线程私有,线程之间互不影响。

public class ClassExtendThread {

    public static void main(String[] args){
        Thread t1 = new Customer();
        Thread t2 = new Customer();
        t1.start();
        t2.start();
    }
}

class Customer extends Thread{

    private int account = 10;

    public void run(){
        while (true){
            if(account > 0){
                account--;
                System.out.println("线程:" + Thread.currentThread().getName() + ",执行结果:" + account);
            } else {
                break;
            }
        }
    }
}

    打印输出的结果:

线程:Thread-0,执行结果:9
线程:Thread-0,执行结果:8
线程:Thread-0,执行结果:7
线程:Thread-1,执行结果:9
线程:Thread-1,执行结果:8
线程:Thread-0,执行结果:6
线程:Thread-0,执行结果:5
线程:Thread-1,执行结果:7
线程:Thread-0,执行结果:4
线程:Thread-1,执行结果:6
线程:Thread-0,执行结果:3
线程:Thread-1,执行结果:5
线程:Thread-0,执行结果:2
线程:Thread-1,执行结果:4
线程:Thread-0,执行结果:1
线程:Thread-1,执行结果:3
线程:Thread-0,执行结果:0
线程:Thread-1,执行结果:2
线程:Thread-1,执行结果:1
线程:Thread-1,执行结果:0

    线程Thread-0和Thread-1,各自执行10次,将属性account的值从10减到0,相互之间无影响。

    在main方法中,两次 new Customer(),线程1和线程2各自有一份实例副本。执行的时候,线程对应的栈,保存各自的变量和对象地址的引用。

2.实现Runnable接口

    实现Runnable接口,重写run()方法。创建多线程的时候,可以跟继承Thread相同的功能,线程之间相互不影响。也可以是,线程共享数据。这里只说线程线程共享数据。

public class ClassImplRunnable {

    public static void main(String[] args){
        Student s = new Student(5);
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        Thread t3 = new Thread(s);
        Thread t4 = new Thread(s);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class Student implements Runnable{

    private int score;

    public Student(int score){
        this.score = score;
    }

    @Override
    public void run() {
        while (true){
            if(score > 0){
                score--;
                System.out.println("线程:" + Thread.currentThread().getName() + ", 剩余分数:" + score);
            } else {
                break;
            }
        }
    }
}

    打印输出结果:

线程:Thread-3, 剩余分数:8
线程:Thread-1, 剩余分数:7
线程:Thread-0, 剩余分数:8
线程:Thread-0, 剩余分数:4
线程:Thread-0, 剩余分数:2
线程:Thread-0, 剩余分数:1
线程:Thread-0, 剩余分数:0
线程:Thread-1, 剩余分数:5
线程:Thread-3, 剩余分数:6
线程:Thread-2, 剩余分数:3

    线程Thread-0、Thread-1、Thread-2、Thread-3,共享一份对象实例,将score的值从10减到0。

    在main方法中,只有一次new Customer()。创建四个线程,传递的参数为Customer对象,此时四个线程共同拥有这个实例对象,执行的时候,相互之间会有影响(涉及到线程安全的问题)。

    从执行的结果可以看到,8出现了两次,而且线程之前无序。这就是多线程之间的数据共享问题。因为线程是并发执行的,同一时间,会有多个线程共同操作数据。如果当前score的值是9,Thread-3在执行的时候,还未来得及将变更的数据写会内存,Thread-0拿到了未变更的数据(score=9),也进行操作,就会出现两个8。

    解决办法,在run方法上synchronized关键字,保证同一时间,只有一个线程能操作变更。

public class ClassImplRunnable {

    public static void main(String[] args){
        Student s = new Student(10);
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        Thread t3 = new Thread(s);
        Thread t4 = new Thread(s);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class Student implements Runnable{

    private int score;

    public Student(int score){
        this.score = score;
    }

    @Override
    public synchronized void run() {
        while (true){
            if(score > 0){
                score--;
                System.out.println("线程:" + Thread.currentThread().getName() + ", 剩余分数:" + score);
            } else {
                break;
            }
        }
    }
}

    打印输出结果:

线程:Thread-1, 剩余分数:9
线程:Thread-1, 剩余分数:8
线程:Thread-1, 剩余分数:7
线程:Thread-1, 剩余分数:6
线程:Thread-1, 剩余分数:5
线程:Thread-1, 剩余分数:4
线程:Thread-1, 剩余分数:3
线程:Thread-1, 剩余分数:2
线程:Thread-1, 剩余分数:1
线程:Thread-1, 剩余分数:0

    关于锁的使用,在这里就不详细描述。在后续的文章中,会详细讲解。

猜你喜欢

转载自blog.csdn.net/fibonacci2015/article/details/84284926