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)效果是一样的,目前就运行结果来看是这样子的!
java线程锁机制_多线程之锁机制相关推荐
- java线程条件变量_多线程同步条件变量(转载)
最近看<UNIX环境高级编程>多线程同步,看到他举例说条件变量pthread_cond_t怎么用,愣是没有看懂,只好在网上找了份代码,跑了跑,才弄明白 #include #include ...
- java 线程 单例_多线程单例模式
多线程单例模式 原文:https://blog.csdn.net/u011726005/article/details/82356538 1. 饿汉模式 使用饿汉模式实现单例是十分简单的,并且有效避免 ...
- java线程顺序输出_多线程按顺序输出ABC
/** * @author mengwen E-mail: meng_wen@126.com * @date 创建时间:2016年8月30日 下午3:10:32 * @version 1.0 * @p ...
- Java并发相关知识(多线程、锁、容器、工具)
目录 一.基础知识 线程之间如何通信? Java内存模型 内存屏障 顺序一致性 CAS实现原理 原子操作 volatile synchronized 实现原理 什么是锁 原子操作类说明 高性能原子类 ...
- java线程同步——竞争条件的荔枝+锁对象
[0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程同步--竞争条件的荔枝+锁对象 的相关知识: 0.2) for full sou ...
- java线程知乎_全网独家!知乎20K点赞的Java并发多线程笔记,简直堪称神仙级文档...
有很多小伙伴都问过我,头条号里的关于java多线程的文章有pdf版本吗?我其实很想弄pdf,但是前段时间一直没时间去折腾,我把每个Java并发编程核心技术的都整理成了一个又一个的文档.昨天也是终于全部 ...
- java查看对象锁级别_对象级别锁 vs 类级别锁(Java)
前言 对于多线程(并发)和Spring Boot这两块在同步进行学习中,在看到使用synchronized关键字使操作同步时,看到和C#中不一样的东西,所以这里呢,就深入学习了下,若有错误之处,还望指 ...
- 自旋锁和互斥锁实例_多线程编程之自旋锁
一.什么是自旋锁 一直以为自旋锁也是用于多线程互斥的一种锁,原来不是! 自旋锁是专为防止多处理器并发(实现保护共享资源)而引入的一种锁机制.自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用 ...
- java 线程间通信方式_「转」JAVA多线程之线程间的通信方式
1. 同步 这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信. public class MyObject { synchronized public void m ...
最新文章
- Django详解之models操作
- Javapinyin4J实现中文名转拼音
- 团队编程项目作业5-小组评分
- 97.PC 的串口是同步还是异步
- 【S操作】老铁留步,干货来了!小总结云存储云办公云笔记工具——我的云工具选择,供您参考...
- 一部手机失窃引发的惊心动魄的战争,你是个合格的程序猿吗?
- linux替换每个英文字开头为大写,shell脚本,文件里面的英文大小写替换方法。...
- boost::sort模块实现展开排序示例
- 人工智能应用上的九大障碍
- 每日一笑 | 程序员和产品经理打架了,怎么办?
- C++ 内存管理机制
- python免费网络采集_python网络数据采集7 采集一个网站所有的外链
- canvas绘制字体-属性设置2
- [渝粤教育] 西南科技大学 英语写作 在线考试复习资料
- [php基础]Mysql日期函数:日期时间格式转换函数详解
- 机器学习实战1-1 KNN电影分类遇到的问题
- FFmpeg-Python 给视频添加文字
- 基于人脸识别的宿舍门禁系统
- webp的js插件_Vuejs webp图片支持,插件开发过程~ - 简书
- 获取图片外链的方法--网易相册