synchronized互斥锁实例解析
synchronized是Java提供的内置锁,里边有类锁和对象锁;
在静态方法中,我们一般使用类锁,在实例方法中,我们一般使用对象锁。
sleep是带锁沉睡,sleep方法是在阻塞当前线程继续执行的同时,并持有该对象锁,所以该对象的其他同步线程是无法执行的,不是同一个对象的同步线程是可以执行的。
synchronized互斥锁实例解析
1、互斥锁基础使用:防止多个线程同时访问对象的synchronized方法。
只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。
1.1、多个线程调用同一个方法
1.1.1、不加互斥锁时
多个线程,cpu时间片切换的时候,会出现执行到一部分,切换到其它线程的情况,导致输出混乱。
public class MyThread {
public static void main(String[] args) {
MyThread s = new MyThread();
s.thread();
}
public void thread() {
final Printer p = new Printer();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
p.print("1111111111");
} catch (Exception e) {
}
}
}
}, "t1").start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
p.print("2222222222");
} catch (Exception e) {
}
}
}
}, "t2").start();
}
class Printer {
//synchronized
public void print(String str) {
// synchronized(this){
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i));
}
System.out.println();
System.out.println("上面执行的是线程:" + Thread.currentThread().getName());
// }
}
}
}
输出结果片断:
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
11122222221111111222
上面执行的是线程:t2
上面执行的是线程:t1
2111222222222
上面执行的是线程:t2
1111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1111111111
上面执行的是线程:t1
12111111111222222222
上面执行的是线程:t2
上面执行的是线程:t1
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1.1.2、加互斥锁后
package cn.itcast_01_mythread.thread.thread;
/*
* 线程安全问题
*/
public class MyThread {
public static void main(String[] args) {
MyThread s=new MyThread();
s.thread();
}
public void thread(){
final Printer p=new Printer();
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try{
Thread.sleep(10);
p.print("1111111111");
}catch(Exception e){
}
}
}
},"t1").start();
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try{
Thread.sleep(10);
p.print("2222222222");
}catch(Exception e){
}
}
}
},"t2").start();
}
class Printer{
//synchronized
public synchronized void print(String str){
// synchronized(this){
for(int i=0;i<str.length();i++){
System.out.print(str.charAt(i));
}
System.out.println();
System.out.println("上面执行的是线程:"+Thread.currentThread().getName());
// }
}
}
}
输出结果:不会出现错位位置
2222222222
上面执行的是线程:t2
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1111111111
上面执行的是线程:t1
2222222222
上面执行的是线程:t2
1111111111
1.2、多个线程多个锁,升级为类锁
1.2.1、未升级成类锁前
package cn.itcast_01_mythread.thread.thread;
/**
* 多个线程多个锁
* @author HL
*
*/
public class MyThread2 {
private static int age=0;
public static void main(String[] args) {
final MyThread2 m1=new MyThread2();
final MyThread2 m2=new MyThread2();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
m1.printNum("zs");
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
m2.printNum("lisi");
}
});
t1.start();
t2.start();
}
public synchronized void printNum(String name){
try {
if(name.equals("zs")){
age=18;
System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
System.out.println("thread zs do something");
Thread.sleep(1000);
}else{
age=20;
System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
System.out.println("thread lisi do something");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
System.out.println("name="+name+"----age="+age);
}
}
输出结果:
当前调用printNum线程是Thread-0
thread zs do something
当前调用printNum线程是Thread-1
thread lisi do something
当前调用printNum线程是Thread-1
name=lisi----age=20
当前调用printNum线程是Thread-0
name=zs----age=20
2.2.2、加上static关键字,升级为类锁后
当调用setValue方法的时候,执行到sleep方法,sleep是带锁沉睡。sleep在阻塞当前线程(Thread-0)的同时,并持有该对象锁(对象Dirty_read_4 dr),所以该对象的其他同步线程无法执行。
而getValue并没有加锁,所以当Thread-0沉睡时,主线程往下执行,调用getValue方法。
package cn.itcast_01_mythread.thread.thread;
/**
* 多个线程多个锁
* @author HL
*
*/
public class MyThread2 {
private static int age=0;
public static void main(String[] args) {
final MyThread2 m1=new MyThread2();
final MyThread2 m2=new MyThread2();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
m1.printNum("zs");
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
m2.printNum("lisi");
}
});
t1.start();
t2.start();
}
//TODO static 升级成class
public static synchronized void printNum(String name){
try {
if(name.equals("zs")){
age=18;
System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
System.out.println("thread zs do something");
Thread.sleep(1000);
}else{
age=20;
System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
System.out.println("thread lisi do something");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
System.out.println("name="+name+"----age="+age);
}
}
输出结果:
当前调用printNum线程是Thread-0
thread zs do something
当前调用printNum线程是Thread-0
name=zs----age=18
当前调用printNum线程是Thread-1
thread lisi do something
当前调用printNum线程是Thread-1
name=lisi----age=20
2、线程的同步异步问题(多个线程)
2.1、未加前
package cn.itcast_01_mythread.thread.thread;
/*
* 线程的同步异步
*/
public class Sync_Async_3 {
public synchronized void method1(){
try{
System.out.println(Thread.currentThread().getName());
Thread.sleep(4000);
System.out.println("线程0-------执行完毕");
}catch(Exception e){
e.printStackTrace();
}
}
public void method2(){
try{
System.out.println(Thread.currentThread().getName());
System.out.println("线程1--------执行完毕");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
final Sync_Async_3 sa = new Sync_Async_3() ;
/**
* T1线程先持有Sync_Async对象的Lock锁 , t2线程可以以异步的方式调用对象中非synchronized修饰的方法
* 如果在method2上加入synchronized关键字,t2这个时候如果想调用synchronized关键字的方法,就需要等t1执行完毕之后才能调用,也就是同步
* */
Thread t1 = new Thread(new Runnable() {
public void run() {
sa.method1();
}
}) ;
Thread t2 = new Thread(new Runnable() {
public void run() {
sa.method2();
}
}) ;
t1.start();
t2.start();
}
}
输出结果:
Thread-0
Thread-1
线程1--------执行完毕
线程0-------执行完毕
2.2、加锁之后,同步
package cn.itcast_01_mythread.thread.thread;
/*
* 线程的同步异步
*/
public class Sync_Async_3 {
public synchronized void method1(){
try{
System.out.println(Thread.currentThread().getName());
Thread.sleep(4000);
System.out.println("线程0-------执行完毕");
}catch(Exception e){
e.printStackTrace();
}
}
//TODO synchronized
public synchronized void method2(){
try{
System.out.println(Thread.currentThread().getName());
System.out.println("线程1--------执行完毕");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
final Sync_Async_3 sa = new Sync_Async_3() ;
/**
* T1线程先持有Sync_Async对象的Lock锁 , t2线程可以以异步的方式调用对象中非synchronized修饰的方法
* 如果在method2上加入synchronized关键字,t2这个时候如果想调用synchronized关键字的方法,就需要等t1执行完毕之后才能调用,也就是同步
* */
Thread t1 = new Thread(new Runnable() {
public void run() {
sa.method1();
}
}) ;
Thread t2 = new Thread(new Runnable() {
public void run() {
sa.method2();
}
}) ;
t1.start();
t2.start();
}
}
输出结果:
Thread-0
线程0-------执行完毕
Thread-1
线程1--------执行完毕
3、脏读
3.1、不加锁(一个线程)
当调用setValue方法的时候,执行到sleep方法,sleep是带锁沉睡。sleep在阻塞当前线程(Thread-0)的同时,并持有该对象锁(对象Dirty_read_4 dr),所以该对象的其他同步线程无法执行。
而getValue并没有加锁,所以当Thread-0沉睡时,主线程往下执行,调用getValue方法。
package cn.itcast_01_mythread.thread.thread;
/*
* 脏读
*/
public class Dirty_read_4 {
private String weibo_name = "angel" ;
private String weibo_sex = "女" ;
//synchronized
public synchronized void setValue(String weibo_name , String weibo_sex){
System.out.println("执行setValue方法的线程是:"+Thread.currentThread().getName());
this.weibo_name = weibo_name ;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.weibo_sex = weibo_sex ;
System.out.println("setValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
}
public void getValue(){
System.out.println("执行getValue方法的线程是:"+Thread.currentThread().getName());
System.out.println("getValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
}
public static void main(String[] args) throws InterruptedException {
final Dirty_read_4 dr = new Dirty_read_4();
Thread t1 = new Thread(new Runnable() {
public void run() {
dr.setValue("huangxiaoming" , "男");
}
}) ;
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
输出结果:顺序混乱
执行setValue方法的线程是:Thread-0
执行getValue方法的线程是:main
getValue---------weibo_name :huangxiaoming-- weibo_sex : 女
setValue---------weibo_name :huangxiaoming-- weibo_sex : 男
3.2、加锁后(一个线程)
当调用setValue方法的时候,执行到sleep方法,sleep是带锁沉睡。sleep在阻塞当前线程(Thread-0)的同时,并持有该对象锁(对象Dirty_read_4 dr),所以该对象的其他同步线程(getValue())无法执行。只有等到setValue执行完,getValue才会执行。
package cn.itcast_01_mythread.thread.thread;
/*
* 脏读
*/
public class Dirty_read_4 {
private String weibo_name = "angel" ;
private String weibo_sex = "女" ;
//synchronized
public synchronized void setValue(String weibo_name , String weibo_sex){
System.out.println("执行setValue方法的线程是:"+Thread.currentThread().getName());
this.weibo_name = weibo_name ;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.weibo_sex = weibo_sex ;
System.out.println("setValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
}
//TODO synchronized
public synchronized void getValue(){
System.out.println("执行getValue方法的线程是:"+Thread.currentThread().getName());
System.out.println("getValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
}
public static void main(String[] args) throws InterruptedException {
final Dirty_read_4 dr = new Dirty_read_4();
Thread t1 = new Thread(new Runnable() {
public void run() {
dr.setValue("huangxiaoming" , "男");
}
}) ;
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
输出结果:
执行setValue方法的线程是:Thread-0
setValue---------weibo_name :huangxiaoming-- weibo_sex : 男
执行getValue方法的线程是:main
getValue---------weibo_name :huangxiaoming-- weibo_sex : 男
synchronized互斥锁实例解析的更多相关文章
- 悲观的并发策略——Synchronized互斥锁
volatile既然不足以保证数据同步,那么就必须要引入锁来确保.互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁 ...
- pthread mutex 进程间互斥锁实例
共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...
- 线程相关函数(4)-pthread_mutex_lock(), pthread_mutex_unlock() 互斥锁
互斥锁实例: #include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int pthread_mutex ...
- Python 开启线程的2中方式,线程VS进程(守护线程、互斥锁)
知识点一: 进程:资源单位 线程:才是CPU的执行单位 进程的运行: 开一个进程就意味着开一个内存空间,存数据用,产生的数据往里面丢 线程的运行: 代码的运行过程就相当于运行了一个线程 辅助理解:一座 ...
- 转:【Java并发编程】之七:使用synchronized获取互斥锁的几点说明
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17199201 在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访 ...
- Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁
(1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...
- 【Java并发编程】:使用synchronized获取互斥锁
在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确 ...
- 【Java并发编程】之七:使用synchronized获取互斥锁的几点说明
在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确 ...
- 类锁、对象锁、互斥锁与synchronized
本文总结自: https://blog.csdn.net/luckey_zh/article/details/53815694 互斥锁: 若对象有互斥锁,则在任一时刻,只能有一个线程访问对象.类锁.对 ...
随机推荐
- Vue.js——5.生命周期
Vue的生命周期 创建阶段new Vue1,beforeCreate() 表示在实例没有被创建出来之前会执行它加载data和methods2,caeated() data 和methods被初始化了 ...
- java this的用法以及原理
/** * this存在方法中,在方法中被调用. * 且是非static方法中被调用.(this 表示这个类的当前实例,而静态方法不依赖于该类的任何实例,随着类产生而装载,因此方法内不能引用 this ...
- Glob 模式
Glob 是什么 glob 是一种文件匹配模式,全称 global,它起源于 Unix 的 bash shell 中,比如在 linux 中常用的 mv *.txt tmp/ 中,*.txt 就使用到 ...
- 遇到屏蔽selenium的站点如何突破
访问某团外卖,查看下一页商家信息,正常浏览器可以打开, selenium打开就404, 分析请求参数,生成方法最后定位到 rohr*.js 而且有判断selenium特征 抓耳挠腮搞了半天没把这个j ...
- 17.3.12--uillib模块
1---uillib是python标准库中最常用的一个python网络应用资源访问的模块,他可以让你像访问文本一样,读取网页的内容 它的作用是访问一些不需要验证的网络资源和cookie等 uillib ...
- 03 Mybatis:05.使用Mybatis完成CRUD
mybatis框架:共四天 明确:我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式.不管使用XML还是注解配置. 第二天:mybatis基本使用 mybatis的单表crud操作 ...
- nginx中server块的匹配顺序
客户端发出一个http请求时,nginx收到后会取出header头中的host,与nginx.conf中每个server的server_name进行匹配,以此决定到底由哪一个server块来处理这个请 ...
- 第二季第八天 HTML5新特性
在函数内部window.a = a 在全局中就可以拿到这个变量 变量命名.作为函数的参数的时候要详细.调用的时候可以简单点 做全局变量的两个方案 1.绑在标签上data 2.闭包 视频一般都是二进 ...
- 题解【语文1(chin1)- 理理思维】
link 喵~珂朵莉树AC 珂朵莉树?见此处~ 这数据结构太暴力了,所以不讲了 Code: #include<iostream> #include<cstdio> #inclu ...
- 格式化输入 \_\_format\_\_
格式化输入 __format__ 格式化输入 一.__format__ 自定制格式化字符串 date_dic = { 'ymd': '{0.year}:{0.month}:{0.day}', 'dmy ...