java知识点总结之多线程基础-ag真人官方网

java知识点总结之多线程基础-ag真人官方网

来源:php中文网 | 2022-11-15 17:55:47 |

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于多线程的相关内容,同一时刻,可以执行多个线程。例如:使用迅雷可以同时下载多个文件,下面一起来看一下,希望对大家有帮助。

推荐学习:《java视频教程》

一、线程相关概念

1、程序:是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码

2、进程:是指运行中的程序,比如我们使用qq,就启动了一个进程,操作系统就会为 该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。


(资料图)

进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程。

3、线程:是进程创建的,是进程的实体,一个进程可以有多个线程,例如使用迅雷下载文件,迅雷相当于进程,下载的文件相当于线程。

4、单线程:同一时刻,只允许执行一个线程

5、多线程:同一时刻,可以执行多个线程。例如:使用迅雷可以同时下载多个文件。

6、并发:同一时刻,多个任务交替进行。单核cpu实现的多任务就是并发。

7、并行:同一时刻,多个任务同时进行。多核cpu可以实现并行,当任务较多时,并发和并行有可能同时发生。

二、线程基本使用

创建线程有两种方法:

1、继承thread类,重写run方法。

2、实现runnable接口,重写run方法。

注意:thread类实现了runnable接口。

(一) 继承thread类,重写run方法

public class thread01 {    public static void main(string[] args) throws interruptedexception {        cat cat = new cat();        cat.start();        system.out.println("主线程"   thread.currentthread().getname());        for (int i = 1; i <= 5; i  ) {            system.out.println("主线程i="   i);            thread.sleep(1000);        }    }}class cat extends thread{    int times = 0;    @override    public void run() {        while (true) {            system.out.println("你好"   (  times)   thread.currentthread().getname());            try {                thread.sleep(1000);            } catch (interruptedexception e) {                e.printstacktrace();            }            if (times == 5){                break;            }        }    }}

1、在继承thread类,重写了run()方法后,在main方法中需要创建对象,并调用start()方法,启动线程。

2、使用start()方法,会调用重写的run()方法。

3、如果main方法中,start()方法后面还有执行语句,并且run()方法中也有执行语句,main线程中会启动一个子线程thread-0,主线程不会阻塞,主线程与子线程会交替执行。

注意:如果主线程执行完毕,但子线程未执行完,进程不会结束,所有线程执行完毕后,进程自动结束。

4、在主线程中为什么使用start()方法去调用run()方法,而不是直接调用run()方法,因为run()方法是一个普通方法,没有真正启动线程,如果调用run()方法,就会将run()方法执行完毕后,再执行main方法剩余语句,主线程就会阻塞。

所以上面程序都运算结果是:

主线程main主线程i=1你好1thread-0主线程i=2你好2thread-0主线程i=3你好3thread-0主线程i=4你好4thread-0主线程i=5你好5thread-0

(二) 实现runnable接口,重写run方法

public class thread02 {    public static void main(string[] args) {        dog dog = new dog();        thread thread = new thread(dog);        thread.start();    }}class dog implements runnable{    @override    public void run() {        int count = 0;        while (true) {            system.out.println("小狗汪汪叫"   (  count)   thread.currentthread().getname());            try {                thread.sleep(1000);            } catch (interruptedexception e) {                e.printstacktrace();            }            if (count == 10){                break;            }        }    }}

1、因为runnable接口中没有start()方法,所以需要代理

2、先在main方法中需要创建对象,然后创建一个thread对象,将之前创建的对象传入thread,借助thread,调用start()方法,创建线程。

3、建议使用runnable,因为实现runnable接口更加适合多个线程共享一个资源的情况,避免了单继承的限制。

三、线程终止

(一)基本说明

1、当线程执行完任务时会自动退出。

2、也可以使用变量控制run()方法退出终止线程。

(二)操作

1、如果一个线程中的run()方法内部是一个while(true){},即一个无限循环

2、我们可以在线程内部,创建一个boolean属性loop,让loop = true,然后while(loop){}

3、再提供一个setloop方法,这样就可以在其他类中调用setloop方法,改变boolean值,来控制线程终止。

(三)代码演示

public class threadexit {    public static void main(string[] args) throws interruptedexception {        t t = new t();        t.start();        thread.sleep(10000);        t.setloop(false);    }}class t extends thread{    private boolean loop = true;    private int times = 0;        @override    public void run() {        while (loop){            system.out.println("hello"   (  times));            try {                thread.sleep(100);            } catch (interruptedexception e) {                e.printstacktrace();            }        }    }    public void setloop(boolean loop) {        this.loop = loop;    }}

四、线程常用方法

(一)第一组

1、setname:设置线程名称,使之与参数name相同。

2、getname:返回该线程名称。

3、start:使该线程开始执行,java虚拟机底层调用该线程的start0方法。

4、run:调用线程对象的run方法。

5、setpriority:更改线程的优先级。

6、getpriority:获取线程的优先级。

7、sleep:在指定的毫秒数内,让当前正在执行的线程休眠。

8、interrupt:中断线程。

注意事项:

1、start()底层会创建新的线程,调用run(),run()就是一个简单的方法调用,不会启动新线程

2、中断线程一般用于中断正在休眠的线程,并没有真正的结束线程,所以如果线程中每输出内容后,会调用thread.sleep()进行休眠的话,我们可以调用interrupt()方法将其提前唤醒

代码演示:

public class threadmethod01 {    public static void main(string[] args) throws interruptedexception {        t t = new t();        t.setname("邱崇源");        t.setpriority(1);        t.start();        for (int i = 0; i < 5; i  ) {            thread.sleep(1000);            system.out.println("hi"   i);        }        system.out.println(t.getname()   "优先级是"   t.getpriority());        t.interrupt();    }}class t extends thread{    @override    public void run() {        while (true){            for (int i = 0; i < 100; i  ) {                system.out.println(thread.currentthread().getname()   "正在吃包子"   i);            }            try {                system.out.println(thread.currentthread().getname()   "休眠中");                thread.sleep(10000);            } catch (interruptedexception e) {                system.out.println(thread.currentthread().getname()   "被唤醒了");            }        }    }}

(二)第二组

1、yield:是一个静态方法,表示线程的礼让。让出cpu,让其他线程执行,但是不一定成功,因为这取决于cpu,如果cpu认为两个线程可以一起执行,则不进行礼让,所以如果cpu的核数多,并且线程数少,礼让就会大概率失败

2、join:表示线程的插队,假如主线程与子线程正在交替运行,我们想先让子线程执行完毕,然后再让主线程执行,就可以使用线程插队,在主线程中,创建子线程对象,并调用join方法,可以实现线程插队,线程插队一定会成功,先执行完插入线程任务后,再继续执行主线程

代码演示:

public class threadmethod02 {    public static void main(string[] args) throws interruptedexception {        a a = new a();        a.start();        for (int i = 1; i <= 20; i  ) {            system.out.println("主线程(小弟)吃了"   i   "个包子");            thread.sleep(1000);            if (i == 5) {                system.out.println("主线程(小弟)让子线程(大哥)先吃");                a.join();                //thread.yield();                system.out.println("子线程(大哥)吃完了,主线程(小弟)接着吃");            }        }    }}class a extends thread {    @override    public void run() {        for (int i = 1; i <= 20; i  ) {            system.out.println("子线程(大哥)吃了"   i   "个包子");            try {                thread.sleep(1000);            } catch (interruptedexception e) {                e.printstacktrace();            }        }    }}

五、用户线程和守护线程

1、用户线程:也叫工作线程,线程的任务执行完或通知方式结束。

2、守护线程:一般是为工作线程服务的,当所有的用户线程结束守护线程自动结束

应用场景:

如果有两个线程,主线程运行结束,但子线程是无限循环。我们想让主线程结束的同时,子线程也结束,就需要让子线程变成守护线程。

在主线程中,创建子线程对象,并调用setdaemon(true),让子线程变成守护线程。

注意:一定要放在start方法之前

代码演示:

public class threadmethod03 {    public static void main(string[] args) throws interruptedexception {        mydaemonthread mydaemonthread = new mydaemonthread();        mydaemonthread.setdaemon(true);        mydaemonthread.start();        for (int i = 1; i <= 10; i  ) {            system.out.println("宝强正在辛苦工作...");            thread.sleep(1000);        }        system.out.println("宝强回家了,宋喆仓惶跑路...");    }}class mydaemonthread extends thread{    @override    public void run() {        while (true){            system.out.println("马蓉与宋喆正在爽歪歪...");            try {                thread.sleep(1000);            } catch (interruptedexception e) {                e.printstacktrace();            }        }    }}

六、线程的生命周期

1、jdk 中用 thread.state 枚举表示了线程的几种状态

2、线程状态转换图

七、线程的同步

1、应用场景:

假如有100张票,有三个线程同时进入该方法买票,票就有可能超卖。所以我们需要线程同步机制,保证数据在同一时刻,最多有一个线程访问。

可以采取同步方法,在方法中加入synchronized关键字。

也可以采用同步代码块,synchronized(对象){}

注意:synchronized是非公平锁,如果这次第一个线程访问了数据,那么下一次第一个线程也有可能访问到数据。

如果同步方法是非静态的,那么锁可以是this,也可以是其他对象,但要求是同一个对象。

例:synchronized(this)

如果同步方法是静态的,锁为当前类本身。

例:synchronized(类名:class)

2、代码演示:

public class sellticket {    public static void main(string[] args) {        sellticket02 sellticket04 = new sellticket02();        thread thread1 = new thread(sellticket04);        thread thread2 = new thread(sellticket04);        thread thread3 = new thread(sellticket04);        thread1.start();        thread2.start();        thread3.start();    }}class sellticket02 implements runnable {    public static int ticket = 100;    private boolean loop = true;    public synchronized void sell() {        if (ticket <= 0) {            loop = false;            return;        }        system.out.println("卖出了一张票,还剩"   (--ticket)   "张");        try {            thread.sleep(500);        } catch (interruptedexception e) {            e.printstacktrace();        }    }    @override    public void run() {        while (loop) {            sell();        }    }}

八、线程的死锁

1、基本介绍

多个线程都占用了对方的锁资源,但不肯相让,就导致了死锁,在编程中,一定要避免死锁的发生。

2、发生场景:

例如:a和b的面前都各有两道门,a的第一道门是o1,第二道门是o2。b的第一道门是o2,第二道门是o1。他们的面前有两把锁,一个是o1锁,一个是o2锁,假如a抢到了o1锁,b抢到了o2锁,但是他们只可打开各自的第一道门,第二道门都没有打开,那么他们都无法释放自己的锁资源,又不可能相让,因此发生了死锁。

3、代码演示:

public class deadlock_ {public static void main(string[] args) { //模拟死锁现象 deadlockdemo a = new deadlockdemo(true); a.setname("a 线程"); deadlockdemo b = new deadlockdemo(false); b.setname("b 线程");a.start(); b.start(); } }class deadlockdemo extends thread { static object o1 = new object();// 保证多线程,共享一个对象,这里使用 static static object o2 = new object(); boolean flag; public deadlockdemo(boolean flag) {//构造器 this.flag = flag; }@override public void run() {  if (flag) { synchronized (o1) { system.out.println(thread.currentthread().getname()   " 进入 1"); synchronized (o2) { system.out.println(thread.currentthread().getname()   " 进入 2"); } } } else {synchronized (o2) { system.out.println(thread.currentthread().getname()   " 进入 3"); synchronized (o1) {  system.out.println(thread.currentthread().getname()   " 进入 4"); } } } } }

九、释放锁

1、下面操作会释放锁

当前线程的同步方法,同步代码块执行结束。 当前线程在同步代码块,同步方法中遇到break,return。 当前线程在同步代码块,同步方法中出现了未处理的错误或异常,导致异常结束。 当前线程在同步代码块,同步方法中执行的线程对象的wait方法,当前线程暂停,并释放锁。

2、 下面操作不会释放锁

线程执行同步代码块和同步方法时,程序调用thread.sleep(),thread.yield()方法暂停当前线程的执行,不会释放锁。 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。

推荐学习:《java视频教程》

以上就是java知识点总结之多线程基础的详细内容,更多请关注php中文网其它相关文章!

关键词:

ag真人官方网 ag真人官方网的版权所有.

联系网站:920 891 263@qq.com
网站地图