多线程深入讨论问题(阿里云开发者社区学习笔记)

文章介绍了Java中线程的优雅停止,强调了不再推荐使用`stop()`等已废弃的方法,推荐通过共享变量如`flag`来控制线程退出。此外,讲解了守护线程的概念,即当所有非守护线程结束时,守护线程也会自动结束,以GC线程为例。最后讨论了volatile关键字的作用,它保证了变量在多线程环境中的可见性,避免副本操作,但不提供同步控制。
摘要由CSDN通过智能技术生成

优雅的停止线程

在多线程的操作之中如果要启动多线程肯定使用的是Thread类中start()方法,而如果对于多线程需要进行停止处理,Thread类原本提供有stop()方法,但是对于这些方法从JDK1.2版本开始已经将其废除了,而且一直到现在也不再建议出现在你的代码之中,而除了stop()方法之外还有几个方法也禁用了:
‒ 停止多线程:
@Deprecated(since=“1.2”)
public final void stop​()
‒ 销毁多线程: @Deprecated(since=“1.5”,forRemoval=true)
public void destroy​()
‒ 挂起线程:
@Deprecated(since=“1.2”)
public final void suspend​() // 暂停执行
‒ 恢复挂起线程执行:
@Deprecated(since=“1.2”)
public final void resume​()
之所以废除掉这些方法,主要的原因是因为这些方法有可能导致线程的死锁,所以从JDK1.2开始都不建议使用了。如果这个时候要想实现线程的停止需要通过一种柔和的方式来进行
范例:实现线程柔和的停止

public class ThreadDemo{
    static boolean flag = true ;
    public static void main(String args[]){
        new Thread(()->{
            long num = 0;
            while(flag){
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + "正在运行\tnum = "+ num++);
            }
        },"执行线程").start();
        try {
            Thread.sleep(200);// 运行200毫秒
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        flag = false ;//停止线程
    }
}

万一现在有其他的线程去控制这个flag的内容,那么这个时候对于线程的停止不是说停就停的,而是会在执行中判断flag的内容来完成

后台守护进程

现在假设有一个人并且这个人有一个保镖,那么这个保镖一定是在这个人活着的时候进行守护,如果这个人已经死了,保镖没用了。所以在多线程里面可以进行守护线程的定义,也就是说如果现在主线程的程序或者其他的线程还在执行的时候,那么守护线程将一直存在,并且运行在后台状态

在Thread类里面提供有如下的守护线程的操作方法:
‒ 设置为守护线程:public final void setDaemon​(boolean on)
‒ 判断是否为守护线程:public final boolean isDaemon​()

import static java.lang.Integer.MAX_VALUE;

public class ThreadDemo{
    public static void main(String args[]){
        Thread userThread = new Thread(()->{
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int x = 0;x < 10; x ++){
                System.out.println(Thread.currentThread().getName() + "正在运行\tx = " + x);
            }
        },"用户线程"); // 完成核心的业务

        Thread deamonThread = new Thread(()->{
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int x = 0;x < MAX_VALUE ; x ++){
                System.out.println(Thread.currentThread().getName() + "正在运行\tx = "+ x);
            }
        },"守护线程"); // 完成核心的业务
        deamonThread.setDaemo(true); // 设为守护线程
        userThread.start();
        deamonThread.start();
    }
}

可以发现所有的守护线程都是围绕在用户线程周围,如果程序执行完毕了,守护线程也就消失了,在整个JVM里面最大的守护线程就是GC线程

程序执行中GC线程会一直存在,如果程序执行完毕,GC线程也将消失.

volatile关键字

在多线程的定义之中,volatile关键字主要是在属性定义上使用的,表示此属性为直接数据操作,而不进行副本的拷贝处理,这样的话在一些书上就将其错误的理解为同步属性了。

在正常进行变量处理的时候往往会经历如下几个步骤:
‒ 获取变量原有的数据内容副本
‒ 为变量进行数学计算
‒ 将计算后的变量,保存到原始空间之中
而如果一个属性上追加了volatile关键字,表示的就是不使用副本,而是直接操作原始变量,相当于节约了:拷贝副本,重新保存的步骤

volatile可以实现变量更快的处理

class MyThread implements Runnable{
private volatile int ticket = 5; // 直接内存操作
@Override
public void run(){
synchronized(this){
while(this.ticket > 0){
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票处理,ticke = "+this.ticket -- );
}
}
}
}
public class ThreadDemo{
public static void main(String args[]){
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}

面试题:请解释volatiel与synchronized?
‒ volatile主要在属性上使用,而synchronizesd是在代码块和方法上使用的
‒ volatile无法描述同步的处理,它只是一种直接的内存处理,避免了副本的操作,而synchronized是实现同步的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值