第1章 Java多线程技能

进程的概念:

进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动;是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。

线程的概念:

线程可以理解成是在进程中独立运行的子任务。比如QQ.EXE运行时可以有视频线程、下载文件的线程、发送表情的线程、传输数据的线程等。

实现多线程的方式:

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

继承Thread类

1.Thread类实现了Runnable接口,Thread类的结构如下:
public class Thread implements Runnable
2.缺点:Java是单继承的,因此继承Thread类后不能再继承其它接口
用这两种方式创建的线程在工作时的性质是一样的,没有本质的区别。
3.Thread类中的start()方法通知“线程规划器”此线程已经准备就绪,等待调用线程的run()方法。
4.执行start()方法的顺序不代表线程启动的顺序

实例变量与线程安全

自定义线程类中的实例变量针对其它线程可以有共享与不共享之分。

(1) 不共享数据的情况

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

(2) 共享数据的情况

共享数据的情况就是多个线程可以访问同一个变量,比如在实现投票功能的软件时,多个线程可以同时处理同一个人的票数。

public class MyThread1 extends Thread {
    private int count = 5;
public MyThread1(String name) { super(name); this.setName(name); }
@Override public void run() { super.run(); count--; System.out.println("由" + this.currentThread().getName() + "计算,count=" + count); } }
synchronized可以在任意对象及方法上加锁,而加锁的代码称为“互斥区”或“临界区”。

当一个线程想要执行同步方法里面的代码时,线程首先尝试去拿这把锁,如果能够拿到这把锁,那么这个线程就可以执行synchronized里面的代码。如果不能拿到这把锁,那么这个线程就会不断地尝试拿这把锁,直到能够拿到为止,而且是有多个线程同时去争抢这把锁。

非线程安全的概念

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

停止线程

在Java中有以下3种方法可以终止正在运行的线程:
1)使用退出标识,使线程正常退出,也就是当run方法完成后线程终止。
2)使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend及resume一样,都是废弃的方法。
3)使用interrupt方法中断线程。推荐用法。

调用interrupt()方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程。

判断线程是否是停止状态

在Java的SDK中,Thread.java类里提供了两种方法。
1)this.interrupted():测试当前线程是否已经中断。执行后具有将状态标识置清除为false的功能。
2)this.isInterrupted():测试线程Thread对象是否已经中断。但不清楚状态标识。
区别:
this.interrupted()方法的解释:测试当前线程是否已经中断,当前线程是指运行this.interrupted()方法的线程。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

能停止的线程——异常法

调用interrupt()方法可以中断线程,但是后面的方法依然会继续运行。可以通过抛异常来停止运行后面的方法。

在沉睡中停止

如果在sleep状态下停止某一线程,会进入catch语句,并且清除停止状态值,使之变成false。

释放锁的不良后果

使用stop()释放锁将会给数据造成不一致性的结果。另外一个情况就是使一些清理性的工作得不到完成。

暂停线程

暂停线程意味着此线程还可以恢复运行。在Java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行。 suspend与resume方法的缺点: 1.独占 2.不同步

守护线程

在Java中有两种线程,一种是用户线程,另一种是守护线程。
守护线程是一种特殊的线程,它的特殊有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。在Java中通过setDaemon()设置是否是守护线程。