Java教程

java多线程5:线程同步机制(synchronized)

本文主要是介绍java多线程5:线程同步机制(synchronized),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

线程同步

在单线程程序中,后面的线程只能到前面的线程执行完毕才能执行,这不会出现线程抢占问题。但是在多任务的操作系统中,不同优先级的线程抢占CPU资源,这会造成线程共享资源出现资源冲突的问题

我们来引入一个场景:秒杀我们都经常见到过。假如有2个人抢一台手机,势必会造成有一个能抢到,有一个抢不到。假如A运气比较好,抢到了,那么手机数量就会-1,进而变成0,这时候B再来秒杀手机时,程序询问手机数量发现为0,进而反馈:运气真不好,手机被抢走了。

但是如果没有线程同步,当A购买了手机,此时应该手机要减一,但是线程A并没有修改。B也打算下单,程序询问手机数量发现手机还是1(按理来说应该是0),也下单成功。此时就会造成,明明只有一台手机,但是有两个人下单成功的尴尬局面。

因此线程同步是个非常重要的问题:场景也有很多(火车票售卖、淘宝库存、排号系统等等)

这种都必须要求,只有一个线程能访问线程共享资源(剩余票数,库存数,资源剩余),等他执行完毕,才允许其他线程访问

我们来通过买票问题来说明问题

一开始没有线程同步时

public class TreadSafe implements Runnable{

    int num=10;
    @Override
    public void run() {
        while (true){
            if(num>0){
                try {
                    Thread.sleep(100);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("tickets:"+num--);
            } 
        }
    }
    public static void main(String [] args){
        TreadSafe tread =new TreadSafe();
        Thread t1=new Thread(tread);
        Thread t2=new Thread(tread);
        Thread t3=new Thread(tread);
        Thread t4=new Thread(tread);
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

到最后你会发现tickets

在这里插入图片描述

这就是各个线程没有同步的后果,线程1234都有各自的tickets数值,但互相没有同步,会恶意修改num值

那就会出现明明线程1拿走最后一张票了,线程2访问时发现自己的tickets并不是0,继续访问if{}

线程锁

既然问题出现了,那么就有解决问题的方法,那就是给共享资源(票数)上一道锁,当一个线程访问共享资源时,上一道锁,其他线程只能等待前面的线程执行完毕才可以访问。

synchronized关键字可以实现,是基于悲观锁设计的,被synchronized标注的代码块只允许一个线程能访问资源,其他线程等待前面的线程执行完才能进入。

synchronized有两种表示方法

一种是synchronized代码块;一种是synchronized方法

先看第一种

public class TreadSafe implements Runnable{

    int num=10;
    @Override
    public void run() {
        while (true){
            synchronized (""){
                if(num>0){
                    try {
                        Thread.sleep(100);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println("tickets:"+num--);
                }
            }
        }
    }
    public static void main(String [] args){
        TreadSafe tread =new TreadSafe();
        Thread t1=new Thread(tread);
        Thread t2=new Thread(tread);
        Thread t3=new Thread(tread);
        Thread t4=new Thread(tread);
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

我们在之前的例子 中while加入synchronized代码块

synchronized(object){
	//...
}

其实现原理就是,Object为一个任意对象,在每个对象里都有一个标志位(o or 1)。当一个线程访问该代码块时,会先访问对象的标志位,如果标志位为0,说明有其他线程在执行,就自己进入就绪状态直到标志位为1,才能进入该代码块执行,此时标志位又会从1变成0;该代码区又会称为临界区。

这样就能解决问题

在这里插入图片描述

还有一种就是synchronized方法,在前面加上synchronized修饰的方法

synchronized void f(){}

在之前的案例中创建一个类文件,在该类里定义同步方法

public synchronized void doit(){
	if(num>0){
         try {
              Thread.sleep(100);
          }catch (Exception e){
              e.printStackTrace();
          }
          System.out.println("tickets:"+num--);
    }
}

public void run(){
    while(ture){
        doit();
    }
}

这样执行的结果与代码块无异。

这篇关于java多线程5:线程同步机制(synchronized)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!