(1)Java多线程编程核心——Java多线程技能

1、为什么要使用多线程?多线程的优点?

提高CPU的利用率

2、什么是多线程?

3、Java实现多线程编程的两种方式?

a、继承Thread类


public class MyThread01 extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread01");
    }

public static void main(String[] args){
        MyThread01 myThread01 = new MyThread01();
        myThread01.start();
        System.out.println("运行结束");
    }
}


运行结束

MyThread01


多次调用start(),抛异常

public class MyThread01 extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread01");
    }

    public static void main(String[] args){
        MyThread01 myThread01 = new MyThread01();
        myThread01.start();
        myThread01.start();
        System.out.println("运行结束");
    }
}

Exception in thread "main" java.lang.IllegalThreadStateException

at java.lang.Thread.start(Thread.java:705)

at com.season.testthread.MyThread01.main(MyThread01.java:13)

MyThread01

b、实现Runnable接口

public class MyRunnable01 implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable01 run().....");
    }

    public static void main(String[] args){
        Runnable runnable = new MyRunnable01();
        Thread thread = new Thread(runnable);
        thread.start();
        System.out.println("main().....");
    }
}

main().....

MyRunnable01 run().....

4、两种方式的对比?

Thread类本身实现了Runnable接口;

使用Thread类方式创建线程,最大的局限是不支持多继承

5、start() 和 直接调用run() 有什么异同?

Thread.java类中的 start() 通知“线程规划器”此线程已经准备就绪,等待调用线程对象的 run()。run()是由调用线程执行,必须等待 run() 代码执行完成才能执行后面代码,不具有异步效果。

6、非线程安全?

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


(1)不共享数据情况


public class MyThread02 extends Thread {
    private int count = 5;
    public MyThread02(String name){
        this.setName(name);
    }

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

public static void main(String[] args){
        MyThread02 a = new MyThread02("a");
        MyThread02 b = new MyThread02("b");
        MyThread02 c = new MyThread02("c");
        a.start();
        b.start();
        c.start();
    }
}


由 a 计算,count=4

由 a 计算,count=3

由 a 计算,count=2

由 a 计算,count=1

由 a 计算,count=0

由 c 计算,count=4

由 c 计算,count=3

由 c 计算,count=2

由 c 计算,count=1

由 c 计算,count=0

由 b 计算,count=4

由 b 计算,count=3

由 b 计算,count=2

由 b 计算,count=1

由 b 计算,count=0


(2)共享数据情况


public class MyThread03 extends Thread {
    private int count = 5;

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

public static void main(String[] args){
        MyThread03 myThread03 = new MyThread03();
        Thread a = new Thread(myThread03, "a");
        Thread b = new Thread(myThread03, "b");
        Thread c = new Thread(myThread03, "c");
        Thread d = new Thread(myThread03, "d");
        Thread e = new Thread(myThread03, "e");
        a.start();
        b.start();
        c.start();
        d.start();
        e.start();
    }
}


由 c 计算,count=3

由 c 计算,count=2

由 c 计算,count=1

由 c 计算,count=0

由 a 计算,count=3

7、怎么解决非线程安全问题?

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

8、API


currentThread() 返回代码段正在被哪个线程调用的信息。


isAlive() 判断当前线程是否处于活动状态(线程已经启动且尚未终止)。


sleep() 在指定的毫秒内让当前“正在执行的线程”休眠(暂停执行)


getId() 取得线程的唯一标识


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

9、怎么停止线程?

1)、使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

2)、使用 stop() 强行终止线程,不推荐使用这种方法,因为 stop 和 suspend 及 resume 一样,都是作废过期的方法,使用它们可能产生不可预料的结果。如果强行让线程停止则可能使一些请理性的工作得不到完成。另外一个情况就是对锁定的对象进行了“解锁”,导致数据得不到同步处理,出现数据不一致问题。

3)、使用 interrupt() 中断线程。


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

this.interrupted() 测试当前线程是否已经中断状态,执行后具有将状态标识置清除为false的功能。当前线程是指运行 this. Interrupted()
的线程。interrupted() 具有清除状态的功能,所以第二次调用interrupted()
返回值是false。

this.isInterrupted() 测试线程Thread对象是否已经是中断状态,但不清除状态标识。


a、能停止的线程——异常法


public class MyThread04 extends Thread {

@Override

public void run() {

for(int i = 0; i < 500000; i++){

if(this.interrupted()){

System.out.println("已经是停止状态,立即退出!");

break;

}

System.out.println("i = " + (i + 1));

}

System.out.println("for下面语句运行,线程并未停止。");

}

public static void main(String[] args) {

try {

MyThread04 myThread04 = new MyThread04();

myThread04.start();

Thread.sleep(2000);

myThread04.interrupt();

} catch (InterruptedException e) {

System.out.println("main catch{}...");

e.printStackTrace();

}

System.out.println("main() end ....");

}

}


i = 207023

main() end ....

已经是停止状态,立即退出!

for下面语句运行,线程并未停止。


上面的示例虽然停止了线程,但是如果for下面还有语句,还是会继续运行的。

该如何解决语句继续运行的问题呢?


package com.jvm.thread;

public class MyThread04 extends Thread {

@Override

public void 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("进入 MyThread04 类的 run() 的catch{}...");

e.printStackTrace();

}

}

public static void main(String[] args) {

try {

MyThread04 myThread04 = new MyThread04();

myThread04.start();

Thread.sleep(2000);

myThread04.interrupt();

} catch (InterruptedException e) {

System.out.println("main catch{}...");

e.printStackTrace();

}

System.out.println("main() end ....");

}

}


i = 220112

i = 220113

main() end ....

已经是停止状态,立即退出!

进入 MyThread04 类的 run() 的catch{}...

java.lang.InterruptedException

at
com.jvm.thread.MyThread04.run(MyThread04.java:10)


b、使用 return 停止线程

interrupt() 与 return 结合使用


package com.jvm.thread;

public class MyThread05 extends Thread {

@Override

public void run() {

while(true){

if(this.isInterrupted()){

System.out.println("停止了!");

return;

}

}

}

public static void main(String[] args) throws
InterruptedException {

MyThread05 myThread05 = new MyThread05();

myThread05.start();

Thread.sleep(2000);

myThread05.interrupt();

}

}

10、怎么暂停线程?

暂停线程意味着此线程还可以恢复运行。在java多线程中,可以使用suspend() 暂停线程,使用 resume() 恢复线程的执行。

suspend 与 resume 方法的缺点——独占

suspend 与 resume 方法的缺点——不同步

11、线程的优先级

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

设置线程优先级有助于帮组“线程规划器”确定下一次选择哪一个线程来优先执行。

优先级具有随机性。

12、守护线程

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

当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程。

时间: 2024-10-03 22:54:23

(1)Java多线程编程核心——Java多线程技能的相关文章

Java并发编程核心知识体系精讲

第1章 开宗明义[不看错过一个亿]本章一连串设问:为什么学并发编程?学并发编程痛点?谁适合学习本课?本课程包含内容和亮点?首先4大个理由告诉你为什么要学,其实源于JD岗位要求就不得不服了.其次5个痛点+12个亮点,是否说服你要死磕Java并发编程呢?... 第2章 跨越第一座山“线程八大核心”[适用于纵观全貌]八大核心-序章.从本章开始将带你攻克并发编程领域的“第一座大山”:多线程八大核心. 第3章 核心1:实现多线程的正确姿势[解读官方文档,够权威]相信很多小伙伴经常在各大技术博客或者论坛甚至

Java并发编程核心知识体系精讲 完整版

第1章 开宗明义[不看错过一个亿]本章一连串设问:为什么学并发编程?学并发编程痛点?谁适合学习本课?本课程包含内容和亮点?首先4大个理由告诉你为什么要学,其实源于JD岗位要求就不得不服了.其次5个痛点+12个亮点,是否说服你要死磕Java并发编程呢?... 第2章 跨越第一座山“线程八大核心”[适用于纵观全貌]八大核心-序章.从本章开始将带你攻克并发编程领域的“第一座大山”:多线程八大核心. 第3章 核心1:实现多线程的正确姿势[解读官方文档,够权威]相信很多小伙伴经常在各大技术博客或者论坛甚至

Java多线程编程核心 - 对象及变量的并发访问

1.什么是“线程安全”与“非线程安全”? “非线程安全”会在多个线程对同一对象总的实例变量进行并发访问时发生,产生的后果是“脏读”,也就是取到的数据其实是被更改过的. “线程安全”是以获得的实例变量的值是经过同步处理的,不会出现脏读的现象. 2.非线程安全例子?怎么解决? 非线程安全 package com.jvm.thread; public class HasSelfPrivateNum { private int num =  0; public void add(String usern

Java多线程编程核心技术(三)多线程通信

线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督.在本章中需要着重掌握的技术点如下: 使用wait/notify实现线程间的通信 生产者/消费者模式的实现 方法join的使用 ThreadLocal类的使用 1.等待 / 通知机制 通过本节可以学习到,线程与线程之间不是独立的个体,它们彼此

多线程编程、Java I/O系统和Java图形界面编程

多线程编程: 一个正在运行的程序通常称为一个进程,每一个任务称为一个线程,中能够在一个程序内运行多线程的程序称为多线程程序. 线程与进程的区别:①每个进程都需要操作系统为其分配独立的内存空间: ②而同一个进程中的所有线程都在同一内存空间工作,这些线程可以共享同一块内存和系统资源. 线程的创建: 1)通过继承Thread类来创建线程: ①创建一个继承Thread类的类: ②在创建的Thread子类中重写run()方法,在方法中写入想要线程运行的代码: ③创建Thread子类的实例: ④通过调用该实

4.java并发编程艺术-java并发编程基础

java从诞生开始就明智的选择了内置对多线程的支持,这使得java语言相比同一时期的其他语言具有明显的优势.线程作为操作系统调度的最小单元,多个线程能够同时执行,这将显著提升程序的性能,在多核环境中表现的更加明显.但是,过多的创建线程和对线程的不当管理也容易造成问题.本章将着重介绍java并发编程的基础知识,从启动一个线程到线程间不同的通信方式,最后通过简单的线程池示例以及应用(简单的Web服务器)来串联本章所介绍的内容. 1.线程简介 1.1 什么是线程 现代操作系统中在运行一个程序时,会为其

java并发编程12.java内存模型

假设一个线程为变量赋值:variable = 3: 内存模型需要解决一个问题:“在什么条件下,读取variable的线程将看到这个值为3?” 这看上去理所当然,但是如果缺少同步,那么将会有许多因素使得线程无法立即甚至永远,看到另一个线程的操作结果. 如: 1.在编译器中生成的指令顺序,可以与源代码中的顺序不同,此外编译器还会将变量保存在寄存器而不是内存中: 2.处理器可以采用乱序或并行等方式来执行指令: 3.缓存可能会改变将写入变量提交到主内存的次序: 4.而且保存在处理器本地缓存中的值,对于其

3.java并发编程艺术-java内存模型

3.1 java内存模型的基础 3.1.1并发编程模型的两个关键问题 在并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指两个线程 之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递. 在共享内存的并发模型里,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信.在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过发送消息来进行显式进行通信. 同步是指程序中用于控制不同线程

Java并发编程:Java中的锁和线程同步机制

锁的基础知识 锁的类型 锁从宏观上分类,只分为两种:悲观锁与乐观锁. 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作.Java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败. 悲观