java线程锁机制_多线程之锁机制

前言

在Java并发编程实战,会经常遇到多个线程访问同一个资源的情况,这个时候就需要维护数据的一致性,否则会出现各种数据错误,其中一种同步方式就是利用Synchronized关键字执行锁机制,锁机制是先给共享资源上锁,只有拿到锁的线程才可以访问共享资源,其他线程进入等待状态。下面将以实例代码讲解一下

一、wait()、nofity()、nofityAll()讲解

示例代码

package thread;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.concurrent.TimeUnit;/**

* Created by StoneGeek on 2018/5/19.

* 博客地址:http://www.cnblogs.com/sxkgeek* 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。

* 当线程执行notify()/notifyAll()方法时,会唤醒一个处于等待状态该对象锁的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁

* 个人认为synachronized(){}执行完后会释放锁*/

public classWaitNotify {static boolean flag = true;static Object lock = newObject();public static voidmain(String[] args) throws Exception {

Thread waitThread= new Thread(new Wait(), "WaitThread");

waitThread.start();

TimeUnit.SECONDS.sleep(1);

Thread notifyThread= new Thread(new Notify(), "NotifyThread");

notifyThread.start();

}static classWait implements Runnable {public voidrun() {//加锁,拥有lock的Monitor

synchronized (lock) {//当条件不满足时,继续wait,同时释放了lock的锁

while(flag) {

System.out.println(Thread.currentThread().getName()+ "flag is true. wait@"

+ new SimpleDateFormat("HH:mm:ss")

.format(newDate()));try{lock.wait();

System.out.println("此处继续执行"+Thread.currentThread().getName());//flag=true;

} catch(InterruptedException e) {

e.printStackTrace();

}

}//条件满足时,完成工作

System.out.println(Thread.currentThread().getName()+ "flag is false. running@"

+ new SimpleDateFormat("HH:mm:ss").format(newDate()));

}

synchronized (lock){

System.out.println(Thread.currentThread().getName()+"执行结束");

}

}

}//wait()会立刻释放synchronized(obj)中的obj锁,以便其他线程可以执行obj.notify()//但是notify()不会立刻立刻释放sycronized(obj)中的obj锁,必须要等notify()所在线程执行完synchronized(obj)块中的所有代码才会释放这把锁.//yield(),sleep()不会释放锁

static classNotify implements Runnable {public voidrun() {//加锁,拥有lock的Monitor

synchronized (lock) {//获取lock的锁,然后进行通知,通知时不会释放lock的锁,//直到当前线程释放了lock后,WaitThread才能从wait方法中返回

System.out.println(Thread.currentThread().getName()+ "hold lock. notify @"

+ new SimpleDateFormat("HH:mm:ss").format(newDate()));lock.notifyAll();

flag= false;

}//再次加锁

synchronized (lock) {

System.out.println(Thread.currentThread().getName()+ "hold lock again. sleep@"

+ new SimpleDateFormat("HH:mm:ss").format(newDate()));

}

synchronized (lock){

System.out.println(Thread.currentThread().getName()+"执行结束");

}

}

}

}

执行结果如下

1 WaitThread flag is true. wait@ 20:50:392 NotifyThread holdlock. notify @ 20:50:403 NotifyThread holdlock again. sleep@ 20:50:404 NotifyThread执行结束

5 此处继续执行WaitThread

6 WaitThread flagis false. running@ 20:50:407 WaitThread执行结束

解释:

首先创建一个lock对象,然后给这个lock上锁来对多个进程同步,flag是一个标志,用来跳出while循环。

当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。

此时轮到notifythread线程,并且执行notifyAll(),这个意思是能够唤醒所有正在等待这个lock对象的monitor的线程,但是

必须要等notify()所在线程执行完synchronized(obj)块中的所有代码才会释放这把锁,

此时接着waitthread被唤醒,继续执行while循环,执行完之后,由于flag在notifythread中置为false,所以跳出while循环(如果在实例代码的wail()后加flag=true结果是截然不同,由于notirythread进程执行完,此时会一直陷入wait,大家可以试试),

执行console打印5 6 7

notify()与notifyAll()的区别

notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象

的monitor的话,则只能唤醒其中一个线程

而调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程

当时的疑惑

(1)既然notify或者notifyAll需要执行完synchronized块中的内容,那么他还有什么存在的价值的

后来执行完之后,才发现要是没有这个方法,那么synchronized块执行完之后,waitthread还是在等待状态,无法被唤醒。

(2)wait被notify唤醒之后,是接着执行,所以console打印5,并不是从头执行(如果在实例代码的wail()后加flag=true结果是截然不同,由于notirythread进程执行完,waitthread进程重新执行wait方法,此时会一直陷入wait,无其他进程唤醒此进程)

二、sychronized(object)跟sychroized(this)的区别、使用场景

(1)首先创建一个objeck,然后sychronzied(object){}

static Object lock = newObject();

synchronized (lock) {}

这种情况是当多个线程执行不同的代码但是希望分别执行,不同时进行,当然可以加wait、notify来进行锁机制同步

(2)sychronized(this)

synchronized (lock) {}

这种情况是多个线程执行相同的代码,但是希望分别执行.

三、wait()/wait(long)和sleep(long)方法的区别

将示例代码中的lock.wait()改为Thread.sleep(1000),console打印

WaitThread flag is true. wait@ 21:29:49此处继续执行WaitThread

WaitThread flagis true. wait@ 21:29:50此处继续执行WaitThread

WaitThread flagis true. wait@ 21:29:51此处继续执行WaitThread

WaitThread flagis true. wait@ 21:29:52此处继续执行WaitThread

由此说明sleep并没有释放锁。

区别:

1、Sleep(long)是Thread的方法,而wait()/wait(long)是Object的方法

2、Sleep(long)可以放在sychnoized块内也可以不放在里面,但是wait()/wait(long)必须放在语句块内

3、Sleep(long)不释放锁,只是让当前线程暂停一段时间,而wait()/wait(long)是释放锁

4、wait()将当前线程放到阻塞队列,只有调用notify()/notifyAll()方法后,才将其从阻塞队列中移动到就绪队列,等待被CPU调度,而wait(long)方法执行后就是放到阻塞队列,等待时间到期或者被wait()/wait(long)唤醒后就可以放到就绪队列被CPU调度

目前还有一个疑惑,就是线程中的run方法有两个同样的synchroized(lock),是不是跟一个synchroized(lock)效果是一样的,目前就运行结果来看是这样子的!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值