Java多线程读书笔记(一)

Java多线程

1. 进程和线程分别是什么?

  • 进程:受操作系统管理的最小运行单元,任务管理器中的一个个exe可以理解成一个进程。

  • 线程:进程中独立运行的子任务。如qq.exe运行时有很多线程在同时运行,发表情、好友视频、上传文件、聊天、听音乐等。

2. 使用多线程的优点?

  • 提高系统的运行效率:
    最大限度的利用cpu的空闲时间来处理其他的任务。一边编辑文档一边让系统处理打印机打印的数据。
    注意:多线程异步,代码顺序不是执行顺序。

3.start()和run()的区别

  • 专业回答:start()方法是异步的,而run()方法是同步的。
  • start()方法会通知“线程规划器”该线程已经准备就绪,等待调用线程对象的run()方法。Thead.currentThread是该线程。
  • run()方法则会绕过“线程规划器”,由main线程直接调用run()方法。Thread.currentThread是main线程。

比喻:假设我们是在酒店的厨房,run()方法体内容是一道菜的材料,main线程是老板,该线程是厨师,老板雇佣这个厨师(相当于main线程实例化一个该线程对象),老板使用start()方法就是老板通知这个厨师,让厨师去烧这道菜。老板使用run()方法,就是老板拿着这些菜的材料(run方法体),自己烧!start()方法是老板点菜,厨师烧菜,俩人,异步的!run()方法是老板点菜,点完自己烧,一个人,同步的!

* 注意:main线程中如果多个线程启动,它们的start()顺序不代表执行顺序。*

4.使用那种方式开发多线程好?

  • 有两种方式开发多线程,一种继承Threadl,一种实现Runnable接口。实现Runnable接口的方法会好些。
  • 原因:继承Thread的方法具有“局限性”,Java是“单根继承”,为了改变这种限制,可以使用多态,即Runnable接口。
  • 另外,源码中查看,Thread是实现了Runnable接口的,所以构造函数Thread(runnable target)中可以传入一个Thread类的对象。

5.什么是非线程安全?

  • 非线程安全:指多个线程对同一个对象中的同一个实例变量进行操作时会出现“值被更改”,“值不同步”的情况,进而影响程序的执行流程。

6.如何设计线程安全?

  • 给操作实例变量的run方法上加同步锁,synchronized关键字。
  • 这样就能保证每次只有一个线程对该实例变量操作。换句话就是,式多个线程在执行run()方法时,以排队的方式进行处理。
    synchronized可以在任意的对象及方法上加锁,被锁住的这段代码被称为“互斥区”,“临界区”。

7.currentThread()方法

返回代码段正在被哪个线程调用。

8.isAlive()方法

判断当前的线程是否处于活动状态。
活动状态:线程已经启动,尚未终止。线程处于正在运行,或者准备运行的状态。

9.sleep()方法

Thread.sleep(1000);//sleep静态方法,当前线程休眠(暂停执行)1s

10.getId()

取得线程的唯一标志,
main线程Id为1

2017/11/21 10:08:29

停止线程

多线程开发中,对线程的停止进行处理需要一些技巧哦。
Java中有3种方式可以终止运行的线程:
  1. 退出标志
  2. stop()
  3. interrupt()
使用退出标志,线程正常退出,run方法完成后线程终止。
stop()方法属于暴力停止,和suspend(),resume()方法一样属于过期作废的方法,不推荐使用。使用他们可能产生不可预料的结果。
大多数情况下我们使用interrupt()停止一个线程。

1.使用interrupt()终止线程的过程?

在代码中使用myThread.interrupt()方法并不会直接停止线程,只是在当前时间给myThread打上一个状态标志=停止。
所以,我们需要在myThread的run方法中对这个状态标志进行判断,是否标志=停止,然后做处理。

2.这个状态标志要如何判断?

Thread.java中提供两种方式:
1) this.interrupted():测试当前线程是否已经中断
2) this.isInterrupted():测试线程是否已经中断。
两者区别:第一个是 static 方法,第二个不是。造成的影响是:假设在main中初始化并start了myThread线程。然后你用

myThread.interrupt();
system.out.println("是否停止: "+myThread.interrupted());

然后发现打印出来的是:

是否停止:false

啊哦~,不是你想要的true。原因就是interrupted()方法是静态的,不管你写的是mythread.interrupted()还是Thread.interrupted(),程序都只会去判断currentThread的状态,就是判断这里的main线程是否停止。
所以,咱可以把输出语句里的判断改为:

myThread.interrupt();
system.out.println("是否停止: "+myThread.isInterrupted());

结果就是true。
还有个事情,停止当前线程用:

Thread.currentThread().interrupt();
system.out.println("是否停止1: "+Thread.interrupted());
system.out.println("是否停止2: "+Thread.interrupted());

然后结果为:

是否停止1:true 
是否停止2:false

1和2结果怎么会不一样嘞?interrupted()方法调用,有清除状态的功能。2变false。

科研质量办的人真是盛气凌人啊。bula~bula~bula~好讨厌哦

3.具体停止线程的方法?

3.1异常法

MyThread.java:

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
    try {
        for (int i = 0; i < 500000; i++) {
            if (this.interrupted()) {
                System.out.println("已经是停止状态了!我要退出了!");
                throw new InterruptedException();
            }
            System.out.println("i=" + (i + 1));
        }
        System.out.println("我在for下面");
    } catch (InterruptedException e) {
        System.out.println("进MyThread.java类run方法中的catch了!");
        e.printStackTrace();
    }
    }
}

Run.java:

public class Run {   
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end!");
    }   
}

运行结果:

……
i=66316
i=66317
i=66318
i=66319
已经是停止状态了!我要退出了!
进MyThread.java类run方法中的catch了!
java.lang.InterruptedException
end!
    at exthread.MyThread.run(MyThread.java:11)

可以throw new InterruptedException()终止程序。

3.2 沉睡中停止

线程在sleep()时遭遇了myThread.interrupt(),会抛出 InterruptedException。

3.3 stop()暴力停止

stop后抛出java.lang.ThreadDeath异常。此异常不需要显示捕捉。
前头说了,为什么不喜欢用stop(),因为:

如果强制让线程停止则有可能使一些清理性的工作得不到完成。另外锁定的对象得以“解锁”,数据得不到同步的处理,出现数据不一致的情况。

举个栗子:我有三个类,SynObject,MyThread,Run类
SynObject是一个普通的类,有属性:用户名=“a”;密码=”aa”,有可以设置用户名和密码的方法:print(String username,String password)
MyThread类的构造方法中实例化这个SynObject,并且在run方法中调用SynObject的方法来设置用户名=“b”和密码=”bb”。
Run类是我的测试类,创建了一个SynObject(),并且初始化了一个MyThread(synObject)类。
假设SynObject的这个方法里,设置用户名和密码,中间需要20S。而我在Run类main函数里,初始化了线程类,这个线程跑了5s中就被我强制stop()了,最后我在main函数结尾输出的时候,发现SynObject的用户名=”b”和密码=”aa”,我只成功的修改了用户名。数据不一致了。

3.4 return和interrupt()结合停止线程
public class MyThread extends Thread {
    @Override
    public void run() {
            while (true) {
                if (this.isInterrupted()) {
                    System.out.println("停止了!");
                    return;
                }
                System.out.println("timer=" + System.currentTimeMillis());
            }
    }  
}

这个和抛异常法相比,还是抛异常好些。在catch块中我们将异常上抛,使线程停止的事件得以传播。

暂停线程

suspend()暂挂线程,resume()恢复。

1.suspend()和resume()有什么缺点?

缺点一:独占。使用不当,容易造成公共的同步对象的独占,使其他线程无法访问公共的同步对象。举个栗子:
System.out.println()方法,就是一个同步的方法。

public void println(long x) {
    synchronized (this) {
        print(x);
        newLIne();
    }
}

如果我们在一个线程中不停歇地打印,假设打印1-500000。
我们在main方法中写:

MyThread thread = new MyThread();
thread.start();
Thread.sleep(1000);
thread.suspend();
System.out.println("main end!");

线程暂挂了,但是main end!也不会被打印出来,因为println()方法被mythread独占,main线程无法访问。

缺点二:不同步。
假如公共对象没有synchronized锁,不同步。万一暂挂了,run方法只设置完用户名属性,还没来得及设置密码的值,数据自然不一致啦。

2.yield方法干什么?

放弃当前的cpu资源,让给其他任务,但是放弃的时间不确定,有可能刚放弃就又获得CPU时间片。

线程的优先级

1.为什么要给线程设置优先级?

设置优先级有助于“线程规划器”确定下一次选择那一个线程优先执行。优先级较高的线程得到的CPU资源较多。在Java中优先级分1~10这10个等级。常量有:

public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;//一般默认优先级为5
public final static int MAX_PRIORITY = 10;

使用setPriority()设置优先级。myThread.getPriority()获取优先级。

2.线程优先级有哪些特性?

  • 继承性:A线程启动B线程,则B线程的优先级与A是一样的。
  • 规则性:高优先级的线程总是大部分先执行完。但是不代表高优先级的全部先执行完。
  • 随机性:优先级较高的线程不一定每一次都先执行完。
  • 优先级高的线程运行的更快。

3.什么是守护线程?

Java线程中有两种线程:用户线程和守护线程
当进程中不存在任何用户线程时,守护线程自动销毁。典型的守护线程就是垃圾回收线程,典型应用就是GC(垃圾回收器)。

比喻:任何一个守护线程都是整个JVM中所有的非守护线程的保姆,只要有一个非守护线程,守护线程就会继续工作。只有当最后一个非守护线程结束是,守护线程才会随着JVM一同结束工作。

PS:本篇内容属于读书笔记,非常感谢高洪岩老师的《Java多线程编程的核心技术》。这本书非常实用,易懂。如果涉及任何侵权行为,请尽快告诉我。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值