Java多线程的实现方式,以及为什么我们要考虑线程安全问题

我们先看Java中实现多线程的几种方式:

1.继承Thread,重写 run()方法。
2.实现Runnable,实现run()方法。
建议使用实现Runnable接口的方式,因为Java的机制是单继承,多实现
并且我们可以通过setPriority()来设置该线程的执行优先级

/**
 * 通过继承Thread来实现多线程的类
 */
public class ThreadA extends Thread{
    public void run(){
        System.out.println("我是一个通过extends Thread来实现多线程的实例对象");
    }
}
/**
 * Created by Admin on 2019/12/4.
 * 通过实现Runnable来实现多线程的类
 */
public class ThreadB implements Runnable{
    public void run(){
        System.out.println("我是一个通过implements Runnable来实现多线程的实例对象");
    }
}

测试类:

public class ThreadTest {
    public static void main(String[] args) {
        //通过继承Thread类来实现多线程的类A,可以直接new对象执行
        ThreadA a = new ThreadA();
        //通过实现Runnable接口来实现多线程的类B,需要再new Thread(),然后把B的实例封装到Thread中才能执行
        ThreadB b = new ThreadB();
        Thread thread = new Thread(b);
        //我们可以通过setPriority来设置线程优先级,0~10(由低到高)
        a.setPriority(0);
        thread.setPriority(10);
        a.start();
        thread.start();
    }

输出结果:

我是一个通过implements Runnable来实现多线程的实例对象
我是一个通过extends Thread来实现多线程的实例对象

为什么多线程环境下我们需要考虑线程安全问题?

进程是程序执行的最小资源分配单元,每个进程之间的内存空间是独立的,但是同一个进程的不同线程之间却是共享内存资源(方法区和堆内存,栈内存每个线程是相互独立的)。

所以说,所谓的保证线程安全,指的就是同一进程下起了多个线程,如何保证多个线程对内存资源的操作不会同时修改一个共享数据。

加了同步锁的代码块,同一时间只允许同一进程的一个线程使用。

测试Demo如下:

/**
 * 通过继承Thread来实现多线程的类
 */
public class ThreadA extends Thread{
    //用于测试的静态共享变量
    private static Integer count = 10;
    public void run(){
        count--;
        System.out.println("我是一个通过extends Thread来实现多线程的实例对象,当前count为:"+count);
    }
}

测试类:

/**
 * 多线程情况下的测试类
 */
public class SyncTest {
    public static void main(String[] args) {
        ThreadA a1 = new ThreadA();
        ThreadA a2 = new ThreadA();
        ThreadA a3 = new ThreadA();
        a1.start();
        a2.start();
        a3.start();
    }
}

运行结果如下,是有问题的,问题原因是有两个线程同时操作了共享变量count字段:

我是一个通过extends Thread来实现多线程的实例对象,当前count为:8
我是一个通过extends Thread来实现多线程的实例对象,当前count为:8
我是一个通过extends Thread来实现多线程的实例对象,当前count为:7

这就是多线程环境下,对共享资源操作可能存在线程安全的问题。
为了解决这个问题,我们给ThreadA的run方法加上synchronized关键字:

/**
 * 通过继承Thread来实现多线程的类
 */
public class ThreadA extends Thread{
    //用于测试的共享变量
    private static Integer intCount = 10;
    public synchronized void run(){
        intCount--;
        System.out.println("我是一个通过extends Thread来实现多线程的实例对象,当前count为:"+intCount);
    }
}

这个时候我们再执行SyncTest,结果如图:

我是一个通过extends Thread来实现多线程的实例对象,当前count为:9
我是一个通过extends Thread来实现多线程的实例对象,当前count为:8
我是一个通过extends Thread来实现多线程的实例对象,当前count为:7

或者我们可以通过ReentrantLock只给对共享变量有操作的代码加锁

import java.util.concurrent.locks.ReentrantLock;
/**
 * 通过继承Thread来实现多线程的类
 */
public class ThreadA extends Thread{
    //用于测试的共享变量
    private static Integer count = 10;
    private static ReentrantLock lock = new ReentrantLock();
    public  void run(){
        lock.lock();
        count--;
        System.out.println("我是一个通过extends Thread来实现多线程的实例对象,当前count为:"+count);
        lock.unlock();
    }
}

这样也是线程安全的:

我是一个通过extends Thread来实现多线程的实例对象,当前count为:9
我是一个通过extends Thread来实现多线程的实例对象,当前count为:8
我是一个通过extends Thread来实现多线程的实例对象,当前count为:7

你可能感兴趣的:(java,多线程)