多线程二(碌碌无为,平平凡凡)
发布日期:2022-04-11 08:52:50 浏览次数:10 分类:技术文章

本文共 10342 字,大约阅读时间需要 34 分钟。

昨天给大家忘了介绍一个方法 

    线程休眠
        public static void sleep(long time) 让线程休眠指定时间,单位为毫秒
        代码实现:
          

 public class test {                public static void main(String[] args) throws InterruptedException {                    System.out.println("睡觉前");                    //没有创建线程就是主线程休眠                    Thread.sleep(3000);                    //先打印睡觉前,等待三秒打印睡醒了                    System.out.println("睡醒了");                }            }

        多线程的实现:
        

public class MyRunnable implements Runnable{            @Override            public void run() {                for (int i = 0; i < 100; i++) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(Thread.currentThread().getName()+"   "+i);                }            }        }

        测试类:
        

public class Demo {            public static void main(String[] args) {                MyRunnable mr=new MyRunnable();                Thread t1=new Thread(mr);                Thread t2=new Thread(mr);                t2.start();                t1.start();            }        }

    后台线程/守护线程  为了守护普通线程而存在的
        public final void setDaemon(boolean on);设置为守护线程
    代码:第一个线程类
    

public class Thread extends java.lang.Thread {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(getName()+"     "+i);        }    }}

第二个线程类

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

测试类:

public class Demo {    public static void main(String[] args) {        Thread t1=new Thread();        Thread1 t2=new Thread1();        t1.setName("头线程");        t2.setName("尾线程");        //把第二个线程设置为守护线程        //当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了 但不会立马停掉        t2.setDaemon(true);        t1.start();        t2.start();    }}

线程安全问题  

经典案例  买票
    需求:电影院100张票,有三个窗口(三个线程),设计一个程序买票
        思路:1.定义一个类实现线程接口,里边定义一个变量,票的总数为100
              2.在类中重写run()方法实现买票,代码步骤如下
                A.判断票数大于0,就卖票,并告知是那个窗口卖的
                B.票数-1
                C.卖光线程停止
              3.定义一个测试类Demo,
                1.创建类对象
                2.创建三个线程对象,给出相应线程名称
                3.启动线程
    代码:
    

public class Runnable implements java.lang.Runnable {    //票的数量    private int ticaketCount=100;    @Override    public void run() {        while (true){            if (ticaketCount==0){                //票买完了                break;            }else {                //Thread.currentThread().getName()  线程名称  //ticaketCount  票的数量                ticaketCount--;                System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票");            }        }    }}

Demo测试类:
    

public class Demo {    public static void main(String[] args) {        Runnable ra=new Runnable();        //创建一个对象 三个线程 要是创建三个线程的话就是三百张票        Thread t1=new Thread(ra);        Thread t2=new Thread(ra);        Thread t3=new Thread(ra);        t1.setName("窗口1");        t2.setName("窗口2");        t3.setName("窗口3");        t1.start();        t2.start();        t3.start();    }}

在现实生活中,出票是需要时间的,所以我们应该加上sleep方法,让每个线程执行完毕等待

public class Runnable implements java.lang.Runnable {    //票的数量    private int ticaketCount=100;    @Override    public void run() {        while (true){            if (ticaketCount==0){                //票买完了                break;            }else {                //Thread.currentThread().getName()  线程名称  //ticaketCount  票的数量                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                    e.printStackTrace();                }                ticaketCount--;                System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票");            }        }    }}
public class Demo {    public static void main(String[] args) {        Runnable ra=new Runnable();        //创建一个对象 三个线程 要是创建三个线程的话就是三百张票        Thread t1=new Thread(ra);        Thread t2=new Thread(ra);        Thread t3=new Thread(ra);        t1.setName("窗口1");        t2.setName("窗口2");        t3.setName("窗口3");        t1.start();        t2.start();        t3.start();    }}//窗口2在买票还剩下97张票//窗口1在买票还剩下97张票//窗口3在买票还剩下96张票//窗口2在买票还剩下3张票//窗口1在买票还剩下2张票//窗口3在买票还剩下1张票//窗口2在买票还剩下0张票//窗口1在买票还剩下-1张票//窗口3在买票还剩下-2张票//窗口1在买票还剩下-3张票//窗口3在买票还剩下-4张票//窗口1在买票还剩下-5张票

然后就会出现问题  相同的票   还有负数的票

原因:
    重复:线程开始时,三个线程抢占CPU的执行权,线程一抢到执行权,然后票数--为99,假设现在线程三sleep时间到了,抢到了执行权,执行--为98,但是现在线程一未结束,因为操作的同一个线程,所以就时票数都是98,就会出现重复
    符号:    假设票为1,第一个线程进去抢到CPU,进入沉睡,但第二个线程也抢到了CPU,由于第一个线程还是Sleep,所以对象没有发生改变,所以就会发生同时为1,但是线程1,结束Sleep方法后,执行--为0,对象发生改变,正在沉睡的线程对象也是0,再次执行--就会是-1,之所以会出现我上述的-2,-3,-4...是因为if判断语句中没有加入ticaketCount>=0
为什么会出现这种问题呢?
    多线程操作共享资源
如何解决多线程安全问题呢?
    基本思想:让程序没有安全问题的环境
怎么实现?
    把多条语句操作共享数据的代码锁起来,让任意时刻只能由一个线程执行即可
    JAVA中提供了同步代码块
    
同步代码块 
        锁多条语句操作共享数据,可以使用同步代码块实现
    格式:
        synchronized(任意对象){
            多条语句操作共享数据的代码
        }
    默认情况是打开的,只要有一个线程进去执行代码了,锁就会关闭
    当线程执行完毕,锁就自动打开
同步的好处和弊端:
    好处:解决了多线程的数据安全问题
    弊端:当线程很多时,因为每个线程都会判断同步上的锁,这是很耗费资源的,无形中降低程序的运行效率
代码:

public class Runnable implements java.lang.Runnable {    //票的数量    private int ticaketCount=100;    private  Object obj=new Object();    @Override    public void run() {        while (true){            //锁对象是任意的 , 多个线程必须使用同一把锁            synchronized (obj){                if (ticaketCount==0){                    //票买完了                    break;                }else {                    //Thread.currentThread().getName()  线程名称  //ticaketCount  票的数量                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    ticaketCount--;                    System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票");                }            }        }    }}

Demo测试类:

public class Demo {    public static void main(String[] args) {        Runnable ra=new Runnable();        //创建一个对象 三个线程 要是创建三个线程的话就是三百张票        Thread t1=new Thread(ra);        Thread t2=new Thread(ra);        Thread t3=new Thread(ra);        t1.setName("窗口1");        t2.setName("窗口2");        t3.setName("窗口3");        t1.start();        t2.start();        t3.start();    }}

注意:要是有两个线程对象,需要加入static关键字修饰同步方法:就是把synchronized关键字加到方法上
        格式:
            修饰符synchronized返回值类型方法名(方法参数){}
同步代码块和同步方法的区别
        同步代码块锁住指定代码,同步方法是锁住方法中的所有代码
        同步代码块可以指定锁对象,同步方法不能指定锁对象
     同步方法的锁对象就是this
     代码:
    

public class MyRunnable implements Runnable{    private  static int ticaketCount=100;    @Override    public void run() {        while (true){            if ("窗口一".equals(Thread.currentThread().getName())){                //同步方法                boolean b = synchronizedMethod();                if (b){                    break;                }            }if ("窗口二".equals(Thread.currentThread().getName())){                //同步代码块                synchronized (MyRunnable.class){                    if (ticaketCount==0){                        //票买完了                        break;                    }else {                        //Thread.currentThread().getName()  线程名称  //ticaketCount  票的数量                        try {                            Thread.sleep(100);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        ticaketCount--;                        System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票");                    }                }            }        }    }    private synchronized boolean synchronizedMethod() {        if (ticaketCount==0){            return true;        }else {            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            ticaketCount--;            System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票");            return false;        }    }}

Demo测试类:

public class Demo {    public static void main(String[] args) {        MyRunnable mr=new MyRunnable();        Thread t=new Thread(mr);        Thread t2=new Thread(mr);        t.setName("线程1");        t2.setName("线程2");        t.start();        t2.start();    }}

同步静态方法:就是把synchronized关键字加到静态方法上
    格式:
        修饰符 static synchronized 返回值类型 方法名(方法参数){}
    同步静态方法的锁是  类名.thisLock锁
     JDK1.5之后提供了一个新的锁对象
        void lock; 获得锁
        void unlock;释放锁
     Lock是接口不能被实例化,这里采用了它的实现类ReentrantLock来实例化
     ReentrantLock的构造方法
     ReentrantLocK():创建一个ReentrantLock的实例
代码改进:

public class Runnable implements java.lang.Runnable {    //票的数量    private int ticaketCount=100;    //private  Object obj=new Object();    private ReentrantLock lock =new ReentrantLock();    @Override    public void run() {        while (true){            //锁对象是任意的 , 多个线程必须使用同一把锁            //synchronized (obj){            try {                lock.lock();                if (ticaketCount==0){                    //票买完了                    break;                }else {                    //Thread.currentThread().getName()  线程名称  //ticaketCount  票的数量                        Thread.sleep(100);                    ticaketCount--;                    System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票");                }            } catch (InterruptedException e) {                e.printStackTrace();            }finally {                lock.unlock();            }            //  }        }    }}

Demo测试类:

public class Demo {    public static void main(String[] args) {        Runnable ra=new Runnable();        //创建一个对象 三个线程 要是创建三个线程的话就是三百张票        Thread t1=new Thread(ra);        Thread t2=new Thread(ra);        Thread t3=new Thread(ra);        t1.setName("窗口1");        t2.setName("窗口2");        t3.setName("窗口3");        t1.start();        t2.start();        t3.start();    }}

死锁

    线程死锁就是指两个或者多个线程相互持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行
代码:

public class Test {    public static void main(String[] args) {        Object oa=new Object();        Object ob=new Object();        new Thread(()->{            while (true){                synchronized (oa){                    synchronized (ob){                        System.out.println("oa线程正在运行");                    }                }            }        }).start();        new Thread(()->{            while (true){                synchronized (ob){                    synchronized (oa){                        System.out.println("ob线程正在运行");                    }                }            }        }).start();    }}

转载地址:https://blog.csdn.net/weixin_50991263/article/details/123836497 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:多线程二(线程通信)
下一篇:多线程二 线程常用的方法

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月03日 04时45分45秒