Java 多线程(1)

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

Java 多线程(1)

1. 概述

了解操作系统后,想学 Java多线程 好久了。一开始我学习了《Think In Java》中的多线程,真心讲的很好。但是,有的过于深刻。需要,自己慢慢体会、总结。所以,我又入手了《Java 多线程编程核心技术》。打算,回头再看《Think In Java》。

我计划以《Java 多线程编程核心技术》为线,写一下自己对 Java多线程 的理解。

2. Java线程基础

【1】线程安全

引起线程安全问题的主要因素是 不同线程对共享资源的访问 。线程安全是学习 多线程技术 的一个关键问题。

这里需要明白 什么是对资源的共享访问、什么是不共享。看下面的代码:

package Multithreading;

public class MyThread extends Thread{
    private int count = 2;
    public MyThread(String name){
        super();
        this.setName(name);
    }

    @Override
    public void run() {
        super.run();
        while (count > 0){
            System.out.println(Thread.currentThread().getName() + "\tCount = " + count);
            count--;
        }
    }
}

package Multithreading;

public class Run {
    public static void main(String[] args) {
        MyThread myThread0 = new MyThread("线程-0");
        MyThread myThread1 = new MyThread("线程-1");
        MyThread myThread2 = new MyThread("线程-2");
        myThread0.start();
        myThread1.start();
        myThread2.start();
    }
}

很明显,这里为三个线程 访问的是三个不同 的对象。所以,它们之间没有影响,它们坑定线程安全。运行结果如下:

这里写图片描述

将上面的 Run类 改为如下:

package Multithreading;

public class Run {
    public static void main(String[] args) {
        MyThread task = new MyThread("线程-0");
        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
    }
}

得到如下结果:

这里写图片描述

可以看到这里的 task对象 不再是 资源与线程两种身份,这里它只作为一种资源。所以,下面创建的三个匿名的线程是对同一个资源进行访问的。所以,结果会发生改变,因为 Count <= 0 后其他的线程也发现并退出了。
共享同一个资源会造成 非线程安全。比如,一个线程正要读某共享的资源,而现在调度到一个新的线程执行,这个新线程正好修改那个共享资源。以后,重新调度到原线程读该共享资源时会发现它不是原来所需要的,这就是所谓的 “读写冲突”。如何解决这样的问题呢,可以通过 加锁 机制。。。

【2】this.getName() 的问题

在《Java 多线程编程核心技术》p17,对 this.getName() 方法有点疑问。于是,写代码测试了一下:

package Multithreading;

public class CountOperate extends Thread {

    @Override
    public synchronized void run() {
        super.run();
        System.out.println("CountOperate---begin---CountOperate");
        System.out.println("this.getName()\t" + this.getName());
        System.out.println("this.isAlive()\t" + this.isAlive());
        System.out.println("Thread\t" + Thread.currentThread().getName());
        System.out.println("Thread\t" + Thread.currentThread().isAlive());
        System.out.println("CountOperate----end----CountOperate");
    }
}

package Multithreading;

public class Run {
    public static void main(String[] args) {
        CountOperate countOperate = new CountOperate();
        countOperate.start();
        Thread thread1 = new Thread(countOperate);
        thread1.start();
    }
}

运行结果如下:

这里写图片描述

分析结果可以看到,Thread类 对线程的命名方式,它是从 Thread-0 开始的。比如这里的第一个 Thread对象countOperate ,它的 getName() 方法返回就是 Thread-0。而,第二个 Thread对象thread1,它的 getName() 方法返回就是 Thread-1。知道了这些后,就可以弄懂书上的结果了。

【3】interrupted()isInterrupted()

为了区别它们,先看看它们的声明

public static boolean interrupted() {
    return currentThread().isInterrupted(true); //true 表示清理中断标志
}

public boolean isInterrupted() {
    return isInterrupted(false);    //false 表示不清理中断标志
}

通过分析它们的声明,可以很清楚的认识它们。interrupted() 是静态方法,它可以用来判断当前运行线程的中断标志,可以在调用 currentThread() 看出来。而且,它还每次都清楚中断标志。对于 isInterrupted() 方法,它是用来判断某个 线程对象 的中断标志,且它并不清理中断标志。

【4】异常法停止中断

停止中断的常用方法!

package Multithreading;

public class MyThread extends Thread{

    @Override
    public void run() {
        super.run();
        try {
            for (int i = 0; i < 500000; i++) {
                System.out.println("i = " + i);
                if (this.isInterrupted()) {
                    System.out.println("已经进入停止状态!我要退出!");
                    throw new InterruptedException();
                }
            }
        }catch (Exception e){
            System.out.println("进入退出异常!");
            e.printStackTrace();
        }
    }
}
//ps:注意这里 try-catch 的位置
package Multithreading;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        Thread.sleep(1000);
        myThread.interrupt();
    }
}

【5】suspend 独占

在《Java 多线程编程核心技术》p38,书中说的不是很清楚(或者我的理解有误)。这里,仍然可以通过在最后使用 thread1.resume() 使得可以继续运行。但是,不建议使用 suspend() 和 resume() 方法。

ps:在《Java 多线程编程核心技术》p40,是有一 很大几率 不打印 main end。但是还是有几率输出的。为了测试,可以在 i++; 后面添加 Thread.yield()

【6】线程优先级的继承特性

对于 继承 的理解。这里的继承是说,新的线程在旧的线程上开启而不同于类的继承。

也就是说,在旧线程里启动的新线程拥有旧线程的优先级。

3. 坚持。。。

第一章的结束,用了一上午效率有点低。

一天进步一点点。。。

猜你喜欢

转载自blog.csdn.net/kiss_xiaojie/article/details/72843246