秋招准备-Java-并发编程-同步机制与synchronized(二)

1.线程安全的一些概念

2.同步简述

3.synchronized的使用与说明


1.线程安全的一些概念

    1.正确性

        即某个类的行为与其规范完全一致,意思就是功能不能出错,使用多线程编程在带来性能提高的同时,也会由于多线程之间相互影响而导致的功能出错的情况,因此,线程安全,实际上就是确保,大到程序,小到类的方法的正确性,保证每个功能都按其设计的语义来实现,则可以说线程安全。

    

    2.原子性

        一个操作或多个操作,要么都执行,且执行过程不能被打断,要么就不执行,则为原子性。

        如对基本类型的访问和读写是原子性的。而“读取-修改-写入”(典型i++),“先检查后执行”(if语句)是非原子的

        原子操作是实现线程安全的一种,但一组原子操作的组合并不一定就是线程安全了,仍然需要一定的同步机制做确保。


    3.可见性

        指一个线程修改了共享变量的值,其他线程能够立即得知这个修改。

        主要通过原子类,volatile,synchronized来实现。


    4.有序性

        工作内存与主存同步延迟会导致可见性引起的线程不安全问题,而指令重排序则可能导致由有序性引起的线程不安全问题。

        指令重排序是一种JIT编译器的优化,目的是使处理器内部的运算单元能够尽量被充分利用,可能会将输入的代码进行乱序执行,(可以理解为a++;b++;会分到不同处理器一起执行,那么可能同时,也可能b++;在前。)



2.同步简述

    先从引起线程安全的问题讲起,大多数涉及线程安全的操作,都是基于这两点的。

    1.存在共享数据    2.存在多个线程访问使用共享数据

    因此在多个线程同一时段使用共享数据的时候,就有可能会因为相互干扰而导致出错。

    也许按我们自己写代码的顺序,按我们自己想要的各个线程之间执行的顺序,可以得到想要的结果。

    但是多线程在调用的时候,是受JVM来管理的,我们无法控制,因此,在基于几个线程的某种执行时序下,就有可能会导致错误的结果。

    而同步机制,其实就是通过它,来让线程按我们自己想要的执行顺序来执行,以确保线程安全。

    显然,保证线程安全并不全靠同步机制,从上述引起线程安全的两点来看,还有一些方法能够避开错误。如:

    1.如果不存在共享数据,同样可以使用多线程来实现多个只涉及自身的耗时操作的并发执行,以提高效率。

    2.使用自带的原子类,来实现共享数据的安全性。

    3.使用不可更改的共享数据,即共享数据属于不可变类。

    按我现在的理解,实际中,基本上就基于两点来考虑线程安全,1则是考虑数据线程私有,2则是考虑同步。并且最主要的也最清晰的方式,就是靠同步机制。

    而同步机制的主要实现,则是靠互斥实现-synchronized,与显示锁实现-Lock

    本章先介绍synchronized,下一站介绍Lock相关。



3.synchronized

    1.synchronized的使用方法

        主要即三种,synchronized代码块,synchronized方法,synchronized静态方法。

        其区别是加的锁对象不一样。

        synchronized有一个作用区域,且有一把锁,且锁是唯一的,只有持有锁,才能进入到作用区域,如果在申请锁时,发现锁已经被别的线程拿走了,就要进入阻塞且等待,直到那个拿锁的线程出作用区域的时候释放锁,然后阻塞状态的线程中的一个才能够获得锁进入作用区。

        synchronized的锁,是对象锁,即任何一个对象都有了一个新的作用,可以用来当锁,Object o = new Object(),那么对象o就可以用来当锁,且o是唯一的,Object o1 = new Object(),这样的o与o1,就是两把完全不同的锁,synchronized(o){……}这样就用o给这个代码块加上锁了,任何用o绑定的代码块,就都需要遵循synchronized的规则,进拿出放,申请拿锁,无则阻塞。

        理解完synchronized的对象锁,那么上述三种用法就是根据需求来用了。写一段实验代码:

public class Main
{
	private static Object o1 = new Object();
	private Object o2 = new Object();
	public static synchronized void staticFuncSyn() {
		try {
			Thread.sleep(2000);
		}catch(Exception ex) {}
		System.out.println("synchronized静态方法实现-对象锁的对象为:类锁Main.class");
	}
	public synchronized void funcSyn(){
		try {
			Thread.sleep(2000);
		}catch(Exception ex) {}
		System.out.println("synchronized方法实现-对象锁的对象:实例出来的对象");
	}
	public void func1() {
		synchronized(o1) {
			try {
				Thread.sleep(2000);
			}catch(Exception ex) {}
			System.out.println("synchronized代码块实现-对象锁的对象:静态对象o1");
		}
	}
	public void func2() {
		synchronized(o2) {
			try {
				Thread.sleep(2000);
			}catch(Exception ex) {}
			System.out.println("synchronized代码块实现-对象锁的对象:成员对象o2");
		}
	}
	public void func3() {
		synchronized(this) {
			try {
				Thread.sleep(2000);
			}catch(Exception ex) {}
			System.out.println("synchronized代码块实现-对象锁的对象:实例出来的对象");
		}
	}
	public static void main(String[] args)
	{
		Main A = new Main();
		Thread th1 = new Thread(new Runnable() {
			public void run() {
				A.staticFuncSyn();
			}
		});
		Thread th2 = new Thread(new Runnable() {
			public void run() {
				A.funcSyn();
			}
		});
		Thread th3 = new Thread(new Runnable() {
			public void run() {
				A.func1();
			}
		});
		Thread th4 = new Thread(new Runnable() {
			public void run() {
				A.func2();
			}
		});
		Thread th5 = new Thread(new Runnable() {
			public void run() {
				A.func3();
			}
		});
		th1.start();th2.start();th3.start();th4.start();th5.start();
		/**
		 * 结果:th1-th4两秒后同时打印,再过了两秒后th5才打印
		 */
	}
}

    2.synchronized的特点

        <1>通过JVM来执行,使用对象锁对代码块进行加锁,结构清晰,出方法块自动解锁。

        <2>阻塞的等待队列无法跳出,一旦拿锁线程不释放锁,则阻塞线程会无限等待下去。

        <3>提供单一的条件队列,通过wait()/notify()/notifyAll()实现中断唤醒机制

        <4>在jdk6以前,当并发量高时,由于大量线程阻塞会导致性能极具下降,而jdk6优化以后,synchronized的性能越来越好。


    3.synchronized的优化(jvm层面)

        锁粗化、锁消除

        偏向锁、轻量级锁、自旋锁

        (未……)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值