1.初识Java多线程

作者: 落叶飞逝的恋 | 来源:发表于2017-09-05 23:16 被阅读46次

    1.进程、线程、多线程的区别

    进程:

    进程(process),是计算机中已运行程序的实体。

    线程:

    线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位

    多线程:

    多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。ps:我们所说的多线程一般指的是单进程内的多线程。

    线程与进程的关系

    2.使用Java中的线程

    Java中实现多线程编程有两种方式:

    • 1.继承java.lang.Thread类
    • 2.实现java.lang.Runnable接口

    两种工作时性质是一样的。只不过使用继承的方式,最大的局限性就是不能支持多继承。

    2.1自定义继承Thread类

    public class CustomerThread extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("customer thread!");
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            CustomerThread customerThread = new CustomerThread();
            customerThread.start();
            System.out.println("main 函数");
        }
    }
    

    2.2自定义继承Runnable接口

    public class CustomerRunable implements Runnable {
        @Override
        public void run() {
            System.out.println("customer runable.");
        }
    }
    
    
    public class Client {
        public static void main(String[] args) {
            CustomerRunable customerRunable = new CustomerRunable();
            Thread thread = new Thread(customerRunable);
            thread.start();
            System.out.println("main 函数");
        }
    }
    

    start()方法说明:the Java Virtual Machine calls the run method of this thread。换句话理解,就是当调用start()方法的时候,也就是告诉JVM此线程已准备完毕。等待JVM安排一个时间来调用Thread类中的run方法。

    如果直接调用Thread.run()方法,那么就变成一个同步方法了,而不是一个异步处理的方式了。

    Thread构造函数

    因为Thread类也实现了Runable接口,所以Thread构造函数也可以传入Thread类。

    3.实例变量与线程安全

    自定义线程类中的实例变量针对其他线程可以共享也可以不共享

    3.1不共享线程实例变量

    public class MyThread extends Thread {
        private int count = 5;
    
    
        public MyThread(String name) {
            super();
            this.setName(name);
        }
    
        @Override
        public void run() {
            super.run();
            while (count > 0) {
                count--;
                System.out.println("由" + this.currentThread().getName() + "计算,count=" + count);
            }
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            MyThread a = new MyThread("a");
            MyThread b = new MyThread("b");
            MyThread c = new MyThread("c");
            a.start();
            b.start();
            c.start();
        }
    }
    

    3.2共享线程实例变量

    public class MyThread extends Thread {
        private int count = 5;
    
    
        public MyThread(String name) {
            super();
            this.setName(name);
        }
    
        @Override
        public void run() {
            super.run();
            count--;
            System.out.println("由" + this.currentThread().getName() + "计算,count=" + count);
        }
    }
    

    去除while的判断条件

    public class Client {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            Thread a = new Thread(myThread, "a");
            Thread b = new Thread(myThread, "b");
            Thread c = new Thread(myThread, "c");
            Thread d = new Thread(myThread, "d");
            a.start();
            b.start();
            c.start();
            d.start();
        }
    }
    
    

    创建一个自定义线程实例,然后把自定义线程实例传递到Thread类中。这样a,b,c,d线程实例就能共享到myThread自定义线程实例的变量了。

    3.3线程安全

    如果不对资源进行访问控制,多个线程之间会出现线程竞争。为了避免出现这样的情况。可以在类上或者方法上使用synchronized关键字描述。意味给方法进行加锁。

    加锁这段代码称为"互斥区"或"临界区"。

    4.currentThread

    currentThread可返回代码段正被哪个线程调用信息。

    5.isAlive

    判断当前的线程是否处于活动状态。

    活动状态就是线程已经启动且尚未终止。处于正在运行或者准备开始运行的状态就是true。

    6.sleep

    在指定毫秒内让当前“正在执行的线程”暂停。

    7.getId

    取得线程的唯一标识

    8.停止线程

    interrupt()方法是中断线程。但是这个方法不会终止一个正在运行的线程,还需要加入一个判断才能完成线程的停止。

    8.1判断线程是否停止状态

    Thread类中提供了两种方法来判断线程的状态是不是停止的。

    • 1.静态方法interrupted()

    判断当前线程的状态。但是这个方法如果被连续调用两次。第二次返回的状态为false。(在第一次调用已清除了其中断状态后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)

    /**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    
    • 2.实例方法isInterrupted()

    该方法再调用完之后,并不会清除状态标志。所以无论连续调用几次结果都是一样。

    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    

    8.2代码演示

    在实际的代码里,根据中断的状态来执行代码的停止。

    public class CustomerThread extends Thread {
        @Override
        public void run() {
            super.run();
            for (int i = 0; i < 100; i++) {
                if (this.isInterrupted()) {
                    System.out.println("已接收到停止命令!");
                    break;
                }
                System.out.println(String.format("i=%s", i));
            }
            System.out.println("哈哈,我还在...");
        }
    }
    
    public class Client {
        public static void main(String[] args) throws InterruptedException {
            CustomerThread thread = new CustomerThread();
            thread.start();
            Thread.sleep(20);
            thread.interrupt();
            System.out.println(thread.isInterrupted());
            System.out.println("main函数执行完毕!");
    
        }
    }
    
    ...
    i=48
    已接收到停止命令!
    哈哈,我还在...
    true
    main函数执行完毕!
    

    但是上面的方式并不能完全退出程序。比如还会执行for语句下面的sout代码。故需在接收到中断命令后,直接抛出InterruptedException异常。或者直接return

    • try-catch方式
    public class CustomerThread extends Thread {
        @Override
        public void run() {
            super.run();
            try{
                for (int i = 0; i < 100; i++) {
                    if (this.isInterrupted()) {
                        System.out.println("已接收到停止命令!");
                        throw new InterruptedException();
                    }
                    System.out.println(String.format("i=%s", i));
                }
                System.out.println("哈哈,我还在...");
            }
            catch (InterruptedException error){
                System.out.println(error.getMessage());
                error.printStackTrace();
            }
        }
    }
    
    • return方式
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 100; i++) {
            if (this.isInterrupted()) {
                System.out.println("已接收到停止命令!");
                return;
            }
            System.out.println(String.format("i=%s", i));
        }
        System.out.println("哈哈,我还在...");
    }
    

    不过还是建议使用try-catch方式来实现线程的停止。因为catch块可以将异常向上抛出,使得线程停止的事件得以传播。

    9.yield

    yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚放弃,马上又获取CPU时间

    Thread.yield();
    

    10.线程的优先级

    在操作系统中,线程可以划分优先级,优先级高的线程得到的CPU资源越多,也就是CPU优先执行优先级高的线程对象中的任务。

    setPriority()方法

    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }
    

    Java中,线程的优先级分为1-10等级

    Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A时一样的

    11.守护线程

    在Java线程中有两种线程,一种是用户线程,另一种是守护线程。

    守护线程是一种特殊的线程,它的特性是陪伴。当进程中不存在用户线程,那么守护线程也会自动销毁。

    例如GC,是一个守护线程

    相关文章

      网友评论

        本文标题:1.初识Java多线程

        本文链接:https://www.haomeiwen.com/subject/mvapjxtx.html