线程的同步,什么时候释放锁,用什么语句可以停下当前线程?

  • Post author:
  • Post category:其他




一、先看两个类



1 、Ticket ,它实现了Runnable接口

package thread;

public class Ticket implements Runnable{

    private int tick=100;


    @Override
    public void run() {
        try {
            printTick();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void printTick() throws InterruptedException {
        while (true){
            if (tick>0){
                System.out.println(Thread.currentThread().getName()+"---tick为:  "+tick--);
            }else {
                break;

            }
        }
    }
}



2 、测试类

package thread;

public class Test01 {

    public static void main(String[] args) {
        Ticket ticket=new Ticket();

		//创建三个线程
        Thread thread1=new Thread(ticket);
        Thread thread2=new Thread(ticket);
        Thread thread3=new Thread(ticket);
		//为三个线程起名字
        thread1.setName("tick窗口1");
        thread2.setName("tick窗口2");
        thread3.setName("tick窗口3");
		//start线程,让这三个线程到就绪状态(线程的状态) 
        thread1.start();
        thread2.start();
        thread3.start();


    }
}



执行测试类Test1 的 main函数,执行结果:

在这里插入图片描述



此时线程是不安全的,多个线程访问同一个资源(ticket对象里的属性tick),可能线程一执行到中间某个时刻,线程二就进来访问了同一个资源。



如果线程一在改数据之前,线程二就访问了数据,此时线程一和线程二的拿到的数据是一样的,但在线程一执行完数据的修改操作后,这时线程一和线程二拿到的数据就不一样了,也就是不同步。



也就会出现上面的运行结果。



二、那怎么让它同步?

  • 用锁,同一个资源的多个线程共用一把锁。
  • 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
  • 在代码上的体现就是把public void printTick() throws InterruptedException 方法改为public synchronized void printTick() throws InterruptedException
package thread;

public class Ticket implements Runnable{

    private int tick=100;


    @Override
    public void run() {
        try {
            printTick();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void printTick() throws InterruptedException {
        while (true){
            if (tick>0){
                System.out.println(Thread.currentThread().getName()+"---tick为:  "+tick--);
            }else {
                break;

            }
        }
    }
}


这次的运行结果:


在这里插入图片描述



从结果上看是线程安全了,但是只有一个线程在执行,为什么?



因为线程一执行之后一直拿着锁,没有释放。



三、怎么才能让线程一释放锁?



1. 当前线程的同步方法、同步代码块执行结束后,会释放锁


我们把while循环拿掉,这样就可以演示这种情况。

package thread;

public class Ticket implements Runnable{

    private int tick=100;
    
    @Override
    public void run() {
        try {
            printTick();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void printTick() throws InterruptedException {
            if (tick>0){
                System.out.println(Thread.currentThread().getName()+"---tick为:  "+tick--);
            }
        
    }
}


while循环拿掉后的运行结果:


在这里插入图片描述



2.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

package thread;

public class Ticket implements Runnable{

    private int tick=100;

    @Override
    public void run() {
        try {
            printTick();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void printTick() throws InterruptedException {
        while (true){
            if (tick>0){
                System.out.println(Thread.currentThread().getName()+"---tick为:  "+tick--);
                wait(10);
            }else {
                break;
            }
        }
    }


}


加wait(20);掉后的运行结果:





这次就可以看到线程的切换了



四、不会释放锁的操作:


线程执行同步代码块或同步方法时,程序调用Thread.sleep()、

Thread.yield()方法暂停当前线程的执行

package thread;

public class Ticket implements Runnable{

    private int tick=100;

    @Override
    public void run() {
        try {
            printTick();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void printTick() throws InterruptedException {
        while (true){
            if (tick>0){
                System.out.println(Thread.currentThread().getName()+"---tick为:  "+tick--);
                Thread.sleep(2000);
//                Thread.yield();
            }else {
                break;
            }
        }
    }
}


有Thread.sleep(2000);执行的结果:


有Thread.sleep(2000);执行的结果


有Thread.yield();执行的结果:


在这里插入图片描述


这两种情况都是只有一个线程在运行,就是不释放锁,不让其他线程参与进来。


有问题欢迎批评指教



版权声明:本文为weixin_50396443原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。