java线程(二)

本文详细介绍了Java线程的各个方面,包括线程的命名、分类(前台与后台)、优先级,以及线程状态转换。强调了线程安全问题,通过synchronized关键字实现线程同步,讲解了wait、notify和notifyAll方法的使用,并提到了线程池和原子性操作在解决线程安全中的应用。
摘要由CSDN通过智能技术生成

线程(一)

线程的名字(setName/getName)

线程的分类

java中,线程可以分为:

前台线程,又叫做执行线程、用户线程

后台线程,又叫做守护线程、精灵线程

在主线程中,创建出来的线程对象,默认就是前台线程,在它启动之前,我们还可以给它设置为后台线程

//在启动线程之前,可以将其设置为后台线程,否则默认是前台线程

t.setDaemon(true);

线程优先级

线程类Thread中,有一个属性,表示线程的优先级 private int priority;

线程的优先级使用int类型数字表示,最大是10,最小是1,默认的优先级是5。

线程组

Java中使用 java.lang.ThreadGroup 类来表示线程组,它可以对一批线程进行管理,对线程组进行操作,同时也会对线程组里面的这一批线程操作。

创建线程组的时候,需要指定该线程组的名字。
也可以指定其父线程组,如果没有指定,那么这个新创建的线程组的父线程组就是当前线程组。

main线程默认属于main线程组

线程状态

在这里插入图片描述
获取状态 getState();

阻塞

sleep();谁调用sleep谁就阻塞

join();谁调用谁执行,调用x.join();代码的线程阻塞

打断阻塞

如果指定了时间,线程阻塞一定的时间后,会自动恢复到RUNNABLE状态,这种情况下,线程的状态为TIMED_WAITING(有限期等待)
如果没有指定时间,线程会一直阻塞着,直到某个条件满足时,才会自动恢复,这种情况下,线程的状态为WAITING(无限期等待)

interrupt方法可以打断线程阻塞

查看线程对象中“打断标识”值的俩个方法:

线程类Thread中的 isInterrupted 方法:

注意,这个非静态方法,只是返回这个“打断标识”值,并且不会对这个值进行清除(true- >false),因为所传参数ClearInterrupted的值为false

线程类Thread中的 interrupted 方法:

注意,这个静态方法,返回这个“打断标识”值,并且会对这个值进行清除(true->false),因为所 传参数ClearInterrupted的值为true

interrupt()、isInterrupted()、interrupted() 的结构关系大致如下
在这里插入图片描述
三者区别

interrupt()方法

其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。

interrupted()方法

作用是测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。

isInterrupted()方法

作用是只测试此线程是否被中断 ,不清除中断状态。

线程安全

JVM内存中的堆区,是一个共享的区域,是所有线程都可以访问的内存空间。

JVM内存中的栈区,是线程的私有空间,每个线程都有自己的栈区,别的先无法访问到自己栈区 的数据。

多线程环境中,如果有俩个线程并发访问堆区中一个对象中的数据,那么这个数据可能会出现和预期结果不符的情况

java里面线程跟进程的关系

main线程与main方法的关系,main线程执行在jvm里的过程以及结束

当JVM启动的时候,会启动一个名为“Main”的线程。程序就会在这个线程上运行,除非用户自己创建了其他线程。

Main线程首先就会寻找"static void main(String[] args)"方法,并且调用这个方法。这个就是程序的进入点。

如果我们希望程序可以并发,那么我们可以创建多线程,并且给予每个线程一些操作。接下来这些线程就会并发的执行这些操作。JVM同时也会创建一些其他的内部线程在“幕后”工作(比如垃圾回收)。

线程两种创建方式(继承Thread类以及实现Runable接口)

创建线程为了提高效率

拿线程名字,取名等等。。。。api

前台线程

后台线程

线程优先级 1-10 默认5

线程的状态

内部枚举出的情况,用

new(创建完线程对象)——》Runable(就绪状态)start()——》Running(Runable) 抢到cpu——》terminated(终止状态)

还可能——》Blocked/Time_waitting(join/sleep(long))/waitting(join)阻塞状态——》time/interrupt被打断——》Running(Runable) 抢到cpu——》terminated(终止状态)

线程同步解决线程不安全的方法

一种广泛方便的方法,其他以后再了解

用 synchronized加锁

synchronized (锁对象){
//操作共享变量的代码,这些代码需要线程同步,否则会有线程安全问题
//…
}

public class Test {
    public static void main(String[] args) {
        MyData myData = new MyData();
        Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                String name = Thread.currentThread().getName();
                synchronized (myData){
                    for (int i = 0; i < 10; i++) {
                        myData.num = i;
                        System.out.println(name + ": " + myData.num);
                    }
                }
            }
        };
        Thread t2 = new Thread("t2"){
            @Override
                public void run() {
                synchronized (myData){
                    for (int i = 100; i < 20000; i++) {
                        myData.num = i;
                    }
                }
            }
        };
        t1.start();
        t2.start();
    }
}

class MyData{
	int num;
}

还可以使用 synchronized 直接修饰一个方法,表示这个方法中的所有代码都需要线 程同步。

synchronized 关键字修饰非静态方法,默认使用 this 当做锁对象,并且不能自己另外指定
synchronized 关键字修饰静态方法,默认使用 当前类的Class对象 当做锁对象,并且不能自己另外指定

Object类中有三个方法: wait()、notify()、notifyAll
当一个对象,在线程同步的代码中,充当锁对象的时候,在 synchronized 同步的代码块中,就可以调用这个锁对象的这三个方法了

三个核心点:
任何对象中都一定有这三个方法
只有对象作为锁对象的时候,才可以调用
只有在同步的代码块中,才可以调用

synchronized 关键字,虽然可以达到线程同步的效果,但是太“霸道”了,只要一个线程拿到了锁对象,那么这个线程无论是在运行状态,还是时间片用完,回到就绪状态,还是sleep休眠,这个线程都是死死的拿着这个锁对象不释放,只有这个线程把线程同步的代码执行完,才会释放锁对象让别的线程使用。

wait 方法可以让拿到的锁的线程,即使代码没执行完,也可以把锁立即给释放

TIMED_WAITING、WAITING、BLOCKED都属于线程阻塞,他们共同的特点是就是线程不执行代码,也不参与CPU的争夺,除此之外,它们还有各自的特点:(重要)
阻塞1,线程运行时,调用sleep或者join方法后,进入这种阻塞,该阻塞状态可以恢复到RUNNABLE状态,条件是线程被打断了、或者指定的时间到了,或者join的线程结束了
阻塞2,线程运行时,发现锁不可用后,进入这种阻塞,该阻塞状态可以恢复到RUNNABLE状态,条件是线程需要争夺的锁对象变为可用了(别的线程把锁释放了)
阻塞3,线程运行时,调用了wait方法后,线程先释放锁后,再进入这种阻塞,该阻塞状态可以恢复到BLOCKED状态(也就是阻塞2的情况),条件是线程被打断了、或者是被别的线程唤醒了(notify方法)

线程调用无参的wait方法,会释放锁并进入等待池,且此时的状态为WAITING,如果线程调用有 参的wait方法,指定一个等待时间,那么线程释放锁后,进入到等待池

当你调用notify时,只有一个等待线程会被唤醒而且它不能保证哪个线程会被唤醒,这取决于线程调度器。

如果你调用notifyAll方法,那么等待该锁的所有线程都会被唤醒,但是在执行剩余的代码之前,所有被唤醒的线程都将争夺锁定

在这里插入图片描述
线程池

java.util.concurrent

线程锁

java.util.concurrentLock

原子性

java.util.concurrent.atomic

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值