首页 > 系统相关 >线程进程2--线程安全-死锁

线程进程2--线程安全-死锁

时间:2024-07-07 13:27:51浏览次数:12  
标签:Thread -- 死锁 线程 thread1 new public

5. Thread类中常用的一些方法

static void sleep:使当前线程阻塞多少毫秒--线程休眠

yield:当前线程让出cpu参与下次竞争--使用yield线程出现交换执行的频率变高了

join加入当前线程上(插入的线程执行完毕后,当前的线程才会执行)

setDaemon()设置线程为守护线程(当所有的线程执行完毕后,守护线程也会终止)

// sleep--阻塞多少时间
public class Method extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++){
            System.out.println(Thread.currentThread().getName()+"-->"+i);
            //休眠1秒--每隔一秒执行
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("------------------");
        }
    }
}

//join--等待线程
    public static void main(String[] args) throws InterruptedException {
        Method thread1 = new Method();
        thread1.setName("线程1");
        Method thread2 = new Method();
        thread2.setName("线程2");
        thread1.start();
        thread2.start();

        thread1.join();// 加入到主线程上--线程1执行完之后再执行main线程.如果主线程需要等待1和2线程的执行结果 做下一步操作时。
        //thread2.join();
        for (int i = 0; i < 20; i++) {
            //Thread.sleep(10);
            System.out.println("main线程" + i);
        }
-------------------------------------------------------------------------------
//setDaemon--守护线程
        Method thread1 = new Method();
        thread1.setName("线程1");
        thread1.setDaemon(true);//设置thread1为守护线程--以主线程为主,当主线程停息的时候守护线程会出现,主线程完毕之前,守护线程也会终止。
        //比如下面的for循环,虽然i打印输出了但是它还要进行判断和i++,在执行判断这个过程时,守护线程就排上了用场
        thread1.start();
     for (int i = 0; i < 20; i++) {
            //Thread.sleep(10);
            System.out.println("main线程" + i);
        }

        thread1.join();// 加入到主线程上--线程1执行完之后再执行main线程.如果主线程需要等待1和2线程的执行结果 做下一步操作时。
        //thread2.join();
        for (int i = 0; i < 20; i++) {
            //Thread.sleep(10);
            System.out.println("main线程" + i);
        }
-------------------------------------------------------------------------------
         Method thread1 = new Method();
        thread1.setName("线程1");
        thread1.setDaemon(true);//设置thread1为守护线程--以主线程为主,当主线程停息的时候守护线程会出现,主线程完毕之前,守护线程也会终止。
        //比如下面的for循环,虽然i打印输出了但是它还要进行判断和i++,在执行判断这个过程时,守护线程就排上了用场
        thread1.start();
     for (int i = 0; i < 20; i++) {
            //Thread.sleep(10);
            System.out.println("main线程" + i);
        }

6. 解决线程安全问题

6.1什么情况下会出现线程安全问题

当多个线程操作同一个资源时,则会出现线程安全问题

6.2java如何解决线程安全问题

第一种方式:使用synchronized自动锁

第二种方式:使用Lock手动锁

使用锁相对于把原来异步转换同步操作。

第一种:使用synchroonized关键字解决

它可以使用在方法上,也可以使用在代码块中

synchroinzed(共享锁对象){

同步代码块。

}

public class MyRunnableAL implements Runnable{
    private int tick = 100;
    
    private Object obj = new Object();
    
    @Override
    public void run() {
        while (true){
            //使用在代码块中
            synchronized (obj){
                if (tick>0){
                    tick--;
                    System.out.println(Thread.currentThread().getName()+" tick:"+tick);
                }else {
                    break;
                }
            }
        }
    }
}
-----------------------------------------------------------------------------
   private int tick = 100;

    //使用在方法上
    @Override
    public void run() {
        while (true){
            setTick();
            if (tick<=0){
                break;
            }
        }
    }

    public synchronized void setTick(){
        if (tick>0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tick--;
            System.out.println(Thread.currentThread().getName()+" tick:"+tick);
        }
    }

-------------------------------------------------------------------------------
public class Test02 {
    public static void main(String[] args) {
        MyRunnableAL myRunnableAL1 = new MyRunnableAL();
        new Thread(myRunnableAL1,"A").start();

        new Thread(myRunnableAL1,"B").start();

        new Thread(myRunnableAL1,"C").start();

        new Thread(myRunnableAL1,"D").start();
    }
}

第二种:使用Lock手动

Lock是一个接口,实现类ReentrantLock

private int tick = 100;
    //手动加锁Lock
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                //加锁
                lock.lock();
                if (tick > 0) {
                    tick--;
                    System.out.println("当前线程对象的名字为:" + Thread.currentThread().getName() + "----剩余:" + tick + "张票");
                } else {
                    break;
                }
            } finally {//确保解锁---防止死锁---finally语句块:无论怎样都会执行的语句块
                //解锁
                lock.unlock();
            }
        }
    }

6.3synchroinzed自动锁和Lock手动锁的区别

synchroinzed可以使用在方法上和代码块中,自动加锁和释放锁,不会出现锁死现象。

Lock只能用在代码块中,需要手动加锁和释放锁,如果不释放锁,会被锁死

比较灵活释放锁放在finally代码块中。

7. 线程死锁问题

线程A拥有所资源a,希望获取到锁资源b,线程B拥有资源b,希望获取锁资源a。

两个线程互相拥有对方希望获取的锁资源。可能会出现程序堵塞。从而造成死锁。

解决:

1.不要使用锁嵌套。

2.设置超时时间。--Lock类中tryLock

3.使用安全java.until.controller下的类。

8. 线程通信

wait方法(等待线程)notify方法(唤醒线程)--必须用在synchronized自动锁

package com.wjy.waitAndNotify;

public class BankCard {
    private double balance;

    private boolean flag;//true:有钱  false:没钱

    //存款--如果有钱先取走(线程等待)
    public synchronized void cun(double money){
        if (flag==true){
            try {
            //属于Object类的方法。进入等待队列  并释放拥有的锁
                wait();//线程等待
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //如果没钱,则存款
        balance+=money;
        System.out.println(Thread.currentThread().getName()+"存钱成功,余额为:"+balance);
        //设置有钱标志--代表可以取钱
        flag=true;
        //唤醒线程--唤醒等待队列中的某个线程
        notify();
    }

    //取款--如果没钱先线程等待
    public synchronized void qu(double money){
        //没钱--先等待
        if (flag==false){
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //有钱--取钱
        balance-=money;
        System.out.println(Thread.currentThread().getName()+"取钱成功,余额为:"+balance);
        //设置没钱标志--代表可以存钱
        flag=false;
        notify();
    }

}
package com.wjy.waitAndNotify;

public class CunThread extends Thread{
    private BankCard bankCard;
    //构造方法--确保都是使用的同一张卡
    public CunThread(BankCard bankCard){
        this.bankCard=bankCard;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            bankCard.cun(300);
        }
    }
}
package com.wjy.waitAndNotify;

public class QuThread extends Thread{
    private BankCard bankCard;
    public QuThread(BankCard bankCard){
        this.bankCard=bankCard;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++){
            bankCard.qu(300);
        }
    }
}
package com.wjy.waitAndNotify;

public class Test01 {
    public static void main(String[] args) {
        BankCard bankCard = new BankCard();
        CunThread cunThread = new CunThread(bankCard);
        cunThread.setName("c");
        QuThread quThread = new QuThread(bankCard);
        quThread.setName("q");
        cunThread.start();
        quThread.start();
    }
}

9. 线程池

new:新建状态

runnable:就绪状态和运行状态

blocked:堵塞状态

waiting:等待状态

timed_waiting:时间等待

terminated:终止

通过调用不同的方法相互转换

标签:Thread,--,死锁,线程,thread1,new,public
From: https://blog.csdn.net/m0_74194490/article/details/140191255

相关文章

  • 前端HTML+CSS
    一、HTML1.什么是html概念:超文本标记性语言(HyperTextMarkupLanguage)--不只是有文本的标签超:超级文本===》不仅仅是普通文本还可以是:文字、图形、动画、声音、表格等。标记性:标记,元素,标签来源:w3c万维网联盟:组织java开源jspython2.作用:制作网页①网页应该......
  • 本地/远程仓库连接
    1.目标了解Git基本概念能够概述git工作流程能够使用Git常用命令【会】熟悉Git代码托管服务能够使用idea操作git【会】1.初始本地仓库:gitinit2.查看状态:gitstatus3.添加工作到暂存区:gitadd.4.提交缓存区到本仓库加以描述:gitcommit-m'描述'5.查看版......
  • 文件自动分类工具
    获取当前工作目录:使用Path().resolve()获取当前工作目录的绝对路径。定义文件类型及其对应的扩展名:types字典存储了各种文件类型及其对应的文件扩展名列表。例如,文档类型包括.doc, .docx, .txt等;图像类型包括.jpg, .jpeg, .png等。遍历当前目录下的所有文件:使用files......
  • C语言 找出 1000 以内的所有完数
    一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6的因子为1,2,3,而6=1+2+3,因此6是“完数”,编程序找出1000以内的所有完数,并按下面格式输出其因子:6itsfactorsare1,2,3这个程序找出1000以内的所有完数,并输出每个完数及其因子。(如果因子和等于该数,则该数为完数。)#i......
  • 建造者模式
    文章目录建造者模式建造者模式的角色案例代码定义产品定义抽象建造者以及具体建造者定义指挥者客户端使用输出结果建造者模式建造者模式属于创造型的模式,用于创建复杂对象,将创建复杂对象的逻辑与对象本身表示分离出来,比如宝马这个产品,需要构建方向盘,轮胎,后备箱等等......
  • 单例模式之懒汉式
    文章目录单例模式(懒汉式)代码懒汉式(线程不安全)懒汉式(线程安全,加锁)双重检查锁(线程安全,推荐)单例模式(懒汉式)懒汉式是符合懒加载的模式,但是会存在线程并发的问题发生,所以还需要一种解决线程并发的机制,比如:加锁等单例模式懒汉式主要的构成是如下单例类私有化构造函数(防......
  • intellij idea安装教程和项目创建
     安装教程:https://blog.csdn.net/2401_84239901/article/details/137701540 IDEA下载地址:https://www.jetbrains.com//idea/download/#section=windows 创建一个简单项目    点击运行之后,多出来target目录 右击运行 也就是都可以运行,这两处 写了个J......
  • P3523 POI2011 DYN-Dynamite
    P3523POI2011DYN-Dynamite小trick,加双倍经验。思路使\(dis\)的最大值最小,可以想到二分\(dis\),然后根据\(dis\)判断可行性。那么可以把问题转化为,所有关键点到选择的点的距离小于\(dis\)的前提下,使得使用的点的个数最小。这就是:P3942将军令考虑设\(f[u]\)为距离......
  • 数学要背的内容
    数学要背的内容常用泰勒公式:\(\sinx=x-{\Large\frac{x^3}{3!}}+o(x^3)\)\(\cosx=1-{\Large\frac{x^2}{2!}+\frac{x^4}{4!}}+o(x^4)\)\(\tanx=x+{\Large\frac{x^3}{3!}}+o(x^3)\)\(\arcsinx=x+{\Large\frac{x^3}{3!}}+o(x^3)\)......
  • C#开发单实例应用程序并响应后续进程启动参数
    C#默认的WinForm模板是不支持设置单实例的,也没有隔壁大哥VB.NET那样有个“生成单个实例应用程序”的勾选选项(VB某些时候要比C#更方便),实现单实例可以有多种方法:检测同名进程:Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName),如果集合的Length>1那就表明已......