线程同步

线程同步

按照百度的简介:
在一般情况下,创建一个线程是不能提高程序的执行效率的,所以要创建多个线程。但是多个线程同时运行的时候可能调用线程函数,在多个线程同时对同一个内存地址进行写入,由于CPU时间调度上的问题,写入数据会被多次的覆盖,所以就要使线程同步。
同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
“同”字从字面上容易理解为一起动作
其实不是,“同”字应是指协同、协助、互相配合。
如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。例如Window API函数SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者。
在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

作用
线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。
当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。
线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

线程同步的方法:
(1)wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
(2)sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉 InterruptedException异常。
(3)notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的 唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
(4)notityAll ():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁, 而是让它们竞争。

wait()方法
简单地说,当我们调用wait()时 -这会强制当前线程等待,直到某个其他线程在同一个对象上调用notify()或notifyAll()。
为此,当前线程必须拥有对象的监视器。根据Javadocs的说法,这可能发生在:
我们已经为给定对象执行了同步实例方法
我们在给定对象上执行了synchronized块的主体
通过为Class类型的对象执行同步静态方法
请注意,一次只有一个活动线程可以拥有对象的监视器。

这个wait()方法带有三个重载签名。我们来看看这些。
(1) wait()
该wait()方法导致当前线程无限期地等待,直到另一个线程要么调用notify()此对象或notifyAll()
(2)wait(long timeout)
使用此方法,我们可以指定一个超时,在该超时之后将自动唤醒线程。可以使用notify()或notifyAll()在达到超时之前唤醒线程。
请注意,调用wait(0)与调用wait()相同。
(3) wait(long timeout,int nanos)
这是另一个提供相同功能的签名,唯一的区别是这个可以提供更高的精度。
总超时时间(以纳秒为单位)计算为1_000_000 *timeout+ nanos。

notify()和notifyAll()

该notify()方法用于唤醒正在等待到该对象的监视器接入线程。

有两种方法可以通知等待线程。

notify()

对于在此对象的监视器上等待的所有线程(通过使用任何一个wait()方法),方法notify()通知任何一个线程任意唤醒。确切唤醒哪个线程的选择是非确定性的 ,取决于实现。

由于notify()唤醒了一个随机线程,因此它可用于实现线程执行类似任务的互斥锁定,但在大多数情况下,实现notifyAll()会更可行。

notifyAll()

此方法只是唤醒正在此对象的监视器上等待的所有线程。

唤醒的线程将以通常的方式完成 - 就像任何其他线程一样。

但是在我们允许它们继续执行之前,总是要定义快速检查继续执行线程所需的条件 - 因为可能存在某些情况下线程被唤醒而没有收到通知(这种情况将在后面的示例中讨论)

用下鸡蛋的实例来理解一下

public class Egg {
    boolean hasEgg = false;
    Object obj = new Object();
    //捡鸡蛋
    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true){
                if(hasEgg){//有鸡蛋
                    System.out.println("捡到鸡蛋!!");
                    hasEgg=false;
                }else {//没有鸡蛋
                    synchronized (obj){
                        System.out.println("等待另一个线程!!!");
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    });

    Thread t1 =new Thread(new Runnable() {
        @Override
        public void run() {
            while (true){
                try {

                    Thread.sleep(2000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("有鸡蛋了!!!!");
                //通知捡鸡蛋线程工作
                hasEgg=true;
                synchronized (obj){
                    obj.notify();
                }
            }
        }
    });


}
public class test {
    public static void main(String[] args) {
            Egg e =new Egg();
            e.t.start();
            e.t1.start();
    }
}

测试结果

等待另一个线程!!!
有鸡蛋了!!!!
捡到鸡蛋!!
等待另一个线程!!!
有鸡蛋了!!!!
捡到鸡蛋!!
等待另一个线程!!!

扩展内容来自于:https://www.jianshu.com/p/1dafbf42cc54

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值