1.1 认识synchronized 关键字

两个线程有单独的工作内存和共同访问的主内存不同

线程安全的概念:

   1.如果多线程访问一个类、对象、方法表现的特征和一个线程访问的结果一致,那么这个类、对象、方法就是线程安全的

    2.线程安全问题是由对象的成员变量和类的静态变量引起的

   3.每个线程对成员变量和静态变量只有读操作,是线程安全的,有写操作,那么就是线程不安全的

package com.caolh.base;


class User {
	private String name;
	private String pass;

	public User(String name, String pass) {
		this.name = name;
		this.pass = pass;
	}

	public synchronized void set(String name, String pass) {
		this.name = name;
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.pass = pass;
		System.out.println(Thread.currentThread().getName() + "-name=" + this.name + "pass=" + this.pass);
	}
}

/**
 * serlet是单例多线程的、Servlet的本身实现并不是一个单例实现、只是容器加载的时候只实例化一次,所造成的单例现象
 *
 * @ClassName: UserServlet 
 * @author: yin.hl
 * @date: 2017年6月4日 上午9:04:24
 */
class UserServlet {

	private User user;

	public UserServlet() {
		user = new User("张三", "123456");
	}

	public void setPass(String name, String pass) {
		user.set(name, pass);
	}
}

/**
 * 
 * 
 * @ClassName: DemoThread00
 * @author: yin.hl
 * @date: 2017年2月19日 下午4:56:07
 */
public class DemoThread00 {
	
	public static void main(String[] args) {

		final UserServlet us = new UserServlet();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				us.setPass("李四", "777777");
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				us.setPass("王五", "888888");
			}
		}).start();
	}
}

如果不加synchronized 那么就线程不安全.

synchronized  的作用是加锁:

 synchronized  的方法执行,首先是去获得锁,第一个线程访问获得锁,其余线程等待,第一个线程执行完,释放锁,其余的线程就会 有锁竞争。

二、对象锁和类锁

synchronized 作用在非静态方法上是对象锁,多个线程不存在锁竞争;作用在静态方法是类锁,多线程访问同一对象存在所竞争

public synchronized static void add() {  // 如果有static ,则 存在锁竞争,打印结果是有先后顺序;反之,同时打印结果


package com.caolh.base;


public class DemoThread02{
	
	private static int count = 0;
	
	//如果是static变量会怎样?
	public synchronized static void add() {
		count++;
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+">count="+count);
	}
	
	public static void main(String[] args) {
		
		/**
		    Synchronized是获得对象锁,如果作用在static类型上,则升级为类锁
		 */
		
		//内部类无法访问非final对象
		/**
		 * 为什么要用final修饰:
		 * 
		 * 内部类对象的生命周期会超过局部变量的生命周期。
		 * 局部变量的生命周期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。
		 * 而内部类对象生命周期与其它类一样:自创建一个匿名内部类对象,系统为该对象分配内存,直到没有引用变量指向分配给该对象的内存,它才会死亡(被JVM垃圾回收)。
		 * 所以完全可能出现的一种情况是:成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。
		 * 
		 * 匿名内部类对象可以访问同一个方法中被定义为final类型的局部变量。
		 * 定义为final后,编译程序的实现方法:对于匿名内部类对象要访问的所有final类型局部变量,都拷贝成为该对象中的一个数据成员。
		 * 这样,即使栈中局部变量已死亡,但被定义为final类型的局部变量的值永远不变,因而匿名内部类对象在局部变量死亡后,照样可以访问final类型的局部变量,因为它自己拷贝了一份,且与原局部变量的值始终一致。
		 */
		final DemoThread02 thread1 = new DemoThread02();
		final DemoThread02 thread2 = new DemoThread02();
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				thread1.add();	//1.同一个对象、同一把锁
			}
		}, "thread1");
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				//thread1.add();	//1、同一个对象、同一把锁
				thread2.add();
			}
		}, "thread2");
		
		t1.start();
		t2.start();
	}
}

三、对象锁的同步和异步

对象锁只针对synchronized 修饰的方法生效

所以thread1和thread2结果同时打印,print2 方法并未参与锁竞争


public class DemoThread03{
	
	//同步执行
	public synchronized void print1() {
		System.out.println(Thread.currentThread().getName()+">hello!");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	//异步执行
	public  void print2() {
		System.out.println(Thread.currentThread().getName()+">hello!");
	}
	
	public static void main(String[] args) throws Exception{
		
		final DemoThread03 thread = new DemoThread03();
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				thread.print1();
			}
		}, "thread1");
		
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				//thread.print1();
			thread.print2();
			}
		}, "thread2");
		
		t1.start();
		t2.start();
	}
}

四、锁重入

同一个线程得到一个对象的锁以后,再访问其他的锁方法,不存在锁竞争


public class DemoThread05{
	
	public synchronized void run1(){
		System.out.println(Thread.currentThread().getName()+">run1...");
		//调用同类中的synchronized方法不会引起死锁
		run2();
	}
	
	public synchronized void run2(){
		System.out.println(Thread.currentThread().getName()+">run2...");
	}
	
	public static void main(String[] args) {
		final DemoThread05 demoThread05 = new DemoThread05();
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				demoThread05.run1();
			}
		});
		thread.start();
	}
}

 五、异常释放锁

/**   
 * 
 * @Title: DemoThread03.java 
 * @Prject: DemoThread
 * @Package: com.liang.demo 
 * @author: yin.hl
 * @date: 2017年2月19日 下午4:56:07 
 * @version: V1.0   
 */
package com.caolh.base;



/**
 * 抛出异常释放锁
 * @author: Kevin
 * @官网: 	www.mimaxueyuan.com
 * @Q Q群:	660567408
 * @Email:	mimaxueyuan@163.com
 * [每天进步一点点、人生带来大改变...]
 * [本代码对应视频地址:http://study.163.com/course/introduction/1004176043.htm]
 */
public class DemoThread07 {
	
	private int i = 0;
	
	public synchronized void run(){
		while(true){
			i++;
			System.out.println(Thread.currentThread().getName()+"-run>i="+i);
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			int k = 10/0;
			
			if (i == 10) {
				throw new RuntimeException();
			}
		}
	}
	
	public synchronized void get(){
		System.out.println(Thread.currentThread().getName()+"-get>i="+i);
	}
	
	public static void main(String[] args) throws InterruptedException {
		final DemoThread07 demoThread07 = new DemoThread07();
		new Thread(new Runnable() {
			@Override
			public void run() {
				demoThread07.run();
			}
		},"t1").start();
		
		//保证t1线程先执行
		//因为同时启动两个线程,不确定哪个先执行的
		Thread.sleep(1000);
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				demoThread07.get();
			}
		},"t2").start();
	}
}

六、synchronized 代码块

包括 类锁、当前对象锁、任意对象锁,代码块控制锁的粒度更细致


package com.caolh.base;


public class DemoThread08 {

	public void run1() {
		synchronized (this) {
			try {
				System.out.println(Thread.currentThread().getName()+">当前对象锁..");
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public void run2() {
		synchronized (DemoThread08.class) {
			try {
				System.out.println(Thread.currentThread().getName()+">类锁..");
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private Object objectLock = new Object();
	public void run3() {
		synchronized (objectLock) {
			try {
				System.out.println(Thread.currentThread().getName()+">任意对象锁..");
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	//测试方法
	public static void test(final int type){
		if(type==1){
			System.out.println("当前对象锁测试...");
		}else if(type==2){
			System.out.println("类锁测试...");
		}else{
			System.out.println("任意对象锁测试...");
		}
		final DemoThread08 demo1 = new DemoThread08();
		final DemoThread08 demo2 = new DemoThread08();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				if(type==1){
					demo1.run1();	
				}else if(type==2){
					demo1.run2();
				}else{
					demo1.run3();
				}
			}
		},"t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				if(type==1){
					demo1.run1();	
				}else if(type==2){
					demo2.run2();
				}else{
					demo1.run3();
				}
			}
		},"t2");
		t1.start();
		t2.start();
	}
	
	public static void main(String[] args) {
//		test(1);
//		test(2);
//		test(3);
		
		final DemoThread08 demo1 = new DemoThread08();
		final DemoThread08 demo2 = new DemoThread08();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				demo1.run2();	
			}
		},"t1");
		t1.start();
		
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				demo2.run1();	
			}
		},"t2");
		t2.start();
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值