【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP

🍔生命周期

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP

🎄线程的安全问题

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP
发现有两个问题,相同的票出现了多次,出现了超出范围的票

🏳️‍🌈原因

首先线程被线程一抢走了
线程一执行到了sleep,会休眠10ms,然后ticket+1,变为了1
然后线程被线程二抢走了
线程二执行到了sleep,会休眠10ms,然后ticket+1,变为了2
然后线程被线程三抢走了
线程三执行到了sleep,会休眠10ms,然后ticket+1,变为了3
现在ticket是3,就会打印3次ticket=3的结果

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP

⭐改进方法

我们把下面的代码给框起来,设置一个线程执行完这个代码块后,其他线程才能执行
【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP

🌺同步代码块

把操作共享数据的代码给锁起来

synchronizd(){
	操作共享数据的代码
}
  • 锁默认打开,有一个线程进去了,锁自动关闭
  • 里面的代码全部执行完毕,线程出来,锁自动打开

我们把之前的代码块用锁包围起来康康效果如何

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP

MyThread.java


public class MyThread extends Thread {

    //表示这个类的所有对象,都共享ticket数据
    static int ticket = 0;//0~99

    //锁的对象,一定要是唯一的
    static Object obj=new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (ticket < 100) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket++;
                    System.out.println(getName() + "正在卖第" + ticket + "张票");
                } else {
                    break;
                }
            }
        }
    }
}

Demo1.java

package IODemo6;

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        //创建线程对象
        MyThread t1=new MyThread();
        MyThread t2=new MyThread();
        MyThread t3=new MyThread();

        //起名字
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}

⭐细节

  1. 锁必须要写到循环里面
  2. 锁对象必须唯一

🌺同步方法

就是把synchronized关键字加到方法上

修饰符 synchronized 返回值类型 方法名(方法参数){
	......
}

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP
MyRunnable.java


public class MyRunnable implements Runnable{
    int ticket=0;

    @Override
    public void run() {
        while (true){
            //同步方法
            if (method()) break;
        }
    }

    public synchronized boolean method(){
        //共享数据 到了末尾
        if (ticket==100){
            return true;
        }else {
            //共享数据 没有到末尾
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket++;
            System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票!!!");
        }
        return false;
    }
}

ThreadDemo.java

public class ThreadDemo {
    public static void main(String[] args) {
        MyRunnable mr=new MyRunnable();

        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);
        Thread t3=new Thread(mr);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)-LMLPHP

11-23 13:30