多线程讲解,没废话

本文深入讲解Java中的线程概念,包括守护线程、线程加入、优先级设置、线程休眠、中断线程等核心功能。同时探讨了线程的生命周期、创建方式及其区别,以及如何通过同步锁和死锁避免竞态条件,确保多线程环境下的数据一致性。

一、线程

1、守护线程’setDaemon(true);

   意思就是当这个java程序子线程或者子线程停止了,守护线程接收到了这个消息,就会马上让守护线程终止,但是守护线程还是会继续执行一下,可以理解为自杀也需要一点时间。

ThreadDaemon td1 = new ThreadDaemon();
        ThreadDaemon td2 = new ThreadDaemon();

        td1.setName("关羽");
        td2.setName("张飞");

        // 设置守护线程
        td1.setDaemon(true);
        td2.setDaemon(true);

        td1.start();
        td2.start();
        
        设置当前main线程为刘备,并且循环5次,让线程能继续走一下。
        Thread.currentThread().setName("刘备");
        for (int x = 0; x < 5; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }

2、线程加入 join

ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        ThreadJoin tj3 = new ThreadJoin();

        tj1.setName("李渊");
        tj2.setName("李世民");
        tj3.setName("李元霸");

        tj1.start();
        try {
            //在启动之后设置join。等待该线程执行完毕,其余线程才能继续执行。
            tj1.join();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        tj2.start();
        tj3.start();
        for (int x = 0; x < 100; x++) {
            System.out.println("main" + x);

        }

3、线程优先级

1-10,默认5 ,但是只是几率设置的高了一点,不是绝对的

方法 tp1.setPriority(10);

        tp2.setPriority(1);

4、线程休眠

@Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(getName() + ":" + x + ",日期:" + new Date());
            // 睡眠
            // 困了,我稍微休息1秒钟
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

5、中断线程 interrupt

ThreadStop ts = new ThreadStop();
        ts.start();

        try {
            //主线程休眠3秒
            Thread.sleep(3000);
            // ts.stop();
            //中断线程,并且该线程继续往后执行,并且抛出异常InterruptedException
            ts.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();

        }


public class ThreadStop extends Thread {
    @Override
    public void run() {
        System.out.println("开始执行:" + new Date());

        // 我要休息10秒钟,亲,不要打扰我哦
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // e.printStackTrace();
            System.out.println("线程被终止了");

        }

//使用interrupt之后的代码也会执行,但是stop就不会执行了。

        for(int i = 0 ; i <  50000 ;i++) {
            System.out.println("结束执行:" + new Date());
        }
    }

}

6、线程礼让

/*
 * public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
 * 让多个线程的执行更和谐,但是不能靠它保证一人一次。
 */
public class ThreadYieldDemo {
    public static void main(String[] args) {
        ThreadYield ty1 = new ThreadYield();
        
        ty1.setName("林青霞");
        new Thread() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(getName() + ":" + x);
                }
            };

        }.start();

       ty1线程中run方法有yield礼让,所以之前的线程基本会先执行完

        ty1.start();
    }

}

礼让

public class ThreadYield extends Thread {
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(getName() + ":" + x);
            Thread.yield();
        }
    }

}


二、线程的生命周期



三、创建线程的另外一种形式,使用Runnable接口

public class MyRunnableDemo {
    
    public static void main(String[] args) {
        
        //创建完成接口runnable的对象
        MyRunnable myRunnable = new MyRunnable();
        //创建线程把Runnable对象放入thread线程里,这个时候这个线程的run就是这个Runnable中的run了
        Thread thread = new  Thread(myRunnable);
        Thread thread2 = new Thread(myRunnable,"欧文");
        thread2.start();
        thread.start();
        
    }

}

    实现Runnable接口

public class MyRunnable implements Runnable {

    @Override
    public void run() {

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }

}

四、 继承Thread和实现Runnable接口区别:

    1.继承有局限性,如果多个线程使用一个线程类容就需要使用静态数据来共享数据。

    2.接口适合扩展:可以创建一个接口用来构造多个线程。构造的线程类容出去Run中的数据共享,也不需要静态。


五、同步锁

     1  、买票,不加同步锁问题

              if (number > 0) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第: " + (number--) + " 张票");

                }

             多个线程执行同一个run方法。判断条件三个线程都能进来。然后都减一了,最后出现0,-1情况


     2、解决这样的问题只需要加同步锁:

            加锁需要对象,即是一把锁。 这种包起来的锁,可以为任意对象,但是多个线程应该持有一把锁,而不是都用自己的锁。所以应该改为:synchronized(obj) 

            synchronized (new Object()) {
                if (number > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第: " + (number--) + " 张票");
                }

            }

           

        3、同步锁可以直接包方法。

                public synchronized void SellTick()

            但是包了之后想与其他的锁使用同一把锁就不能再使用任何对象了,而是this才可以了

       

        4、同步锁包静态方法

            public static synchronized void SellTick()

            要和静态方法使用同一把锁是字节码文件。类名.class

            分析:

                   Person p = new Person();

                    创建对象时候先把字节码文件放入内存,但是静态数据是随着类的加载而加载,这个时候对象也没创建自然不可能是this。所以设置为字节码文件。类名,class


六、死锁

    private boolean flag;


//传入一个true和false

    public DieLock(boolean flag) {
        this.flag = flag;
    }
    
    @Override

    public void run() {

//if就分别执行两个

MyLock.objA  是一个静态属性Object对象

MyLock.objB  是一个静态属性Object对象

    两个线程同时进入,第一个到了ifObjA,第二个线程就到了else ObjeB。这时候B上锁了,线程一就无法走了,线程二也无法获取A了

            if(flag) {
            synchronized (MyLock.objA) {
                System.out.println("if ObjA");
                synchronized (MyLock.objB) {
                    System.out.println("if ObjB");
                }
            }
        }else {
            synchronized (MyLock.objB) {
                System.out.println("else ObjB");
                synchronized (MyLock.objA) {
                    System.out.println("else ObjA");
                }
            }

  七、等待和唤醒

    操作思想:

        1、发送数据,如果没有接收就等着,接收了之后才再次发送数据。

        2、接收数据,如果没有发送数据就等着,有了数据就接收。

发送数据

@Override

    public void run() {
        while(true) {
            synchronized(s) {
                
                //判断是否有值
                if(s.flag) {
                    //有值就等待另外的来获取,不在生产。
                    try {
                        s.wait(); //等待时候会释放锁,再次被唤醒的时候也是这个位置,
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                
                if(x%2==0) {
                    
                    s.name="小兰";
                    s.age = 17;
                }else {
                    s.name="新一";
                    s.age = 18;
                }
                x++;
                //设置为有值
                s.flag = true;
                
                s.notify();        //将等待的s唤醒    但是还需要抢cpu执行权,如果没wait等待就是相当于没有
            }
        }

接收数据

@Override
    public void run() {
        while(true) {
            synchronized (s) {
                
                if(!s.flag) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //有值就打印
                System.out.println(s.name+"--"+s.age);        
                
                s.flag = false;
                
                s.notify();            //唤醒    

                
            }
        }

八、优化

public class Student {

    private String name;
    private int age;
    private boolean flag;
    
    public synchronized void set(String name ,int age) {
        
        if(this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        this.name = name;
        this.age = age;
        
        flag = true;
        
        this.notify();

    }
    public synchronized void get() {
        
        if(!this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        System.out.println(name+"--"+age);
        
        flag = false;
        
        this.notify();
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值