1.初识Java多线程

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,是一个守护线程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容

  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,454评论 1 15
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,957评论 1 18
  • 该文章转自:http://blog.csdn.net/evankaka/article/details/44153...
    加来依蓝阅读 7,353评论 3 87
  • 写在前面的话: 这篇博客是我从这里“转载”的,为什么转载两个字加“”呢?因为这绝不是简单的复制粘贴,我花了五六个小...
    SmartSean阅读 4,730评论 12 45
  • 去年的六月父亲与世长辞!前几天的周年祭恰与父亲节相遇。站在父亲遗像前心绪不宁,脑子里浮现出一句话 : ...
    道心无悔阅读 248评论 0 1