基本上全部的并发模式再解决线程冲突的时候,都是采用序列化访问共享资源的方案。这意味着在给定时刻只容许一个任务访问共享资源。一般这是经过在代码前面添加一条锁语句来实现的,这就使得在一段时间内只有一个任务能够运行这段代码。由于锁语句产生了一种互相排斥的效果,锁着这种机制经常被称为互斥量。java
Java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持。当任务要执行被synchronized关键字保护的代码片断的时候,它将检查锁是否可用,而后获取锁,执行代码,释放锁编程
共享资源通常是以对象形式存在的内存片断,但也能够是文件、输入/输出端口,或者是打印机设备。要控制对共享资源的访问,得先把它包装进一个对象。而后把全部要访问这个资源的方法标记为synchronized。若是某个任务处于一个对标记为synchronized方法的调用中,那么在这个线程从该方法返回以前,其余全部要调用类中任何标记synchronized方法的线程都会被阻塞。多线程
在Java中,每个对象有且仅有一个同步锁。这也意味着,同步锁依赖对象而存在。当咱们调用某个对象的synchronized修饰的方法时,就获取了该对象的同步锁。例如synchronized(obj)方法就获取了obj这个对象的同步锁。并发
不一样线程对同步锁的访问是互斥的。也就是说,在某一个时刻,对象的同步锁只能被一个线程获取到!其余要获取该锁的线程都会被阻塞。知道线程释放了该锁,其余线程才能去获取同步锁,而后执行代码块。详细的synchronized工做原理请见博客:synchronized实现原理ide
synchronized语句计算一个对象引用,试图对该对象完成锁操做,而且在完成所操做前中止处理。当锁操做完成,synchronized语句体获得执行。当语句体执行完毕(不管正常与否),解锁操做自动执行。synchronized常常与方法连用。函数
public synchronized void function(){ //保护函数 }
一种比较好的办法是,若是某个变量由一个线程赋值,并由别的线程引用或赋值,那么全部对该变量的访问都必须在某个synchronized语句或者synchronized方法内,oop
synchronized(this){ //保护代码块 }
有了synchronized关键字,多线程程序的运行结果将变得能够控制。synchronized关键字用于保护共享数据。因此编程时分清共享数据很重要。this
class MyRunable implements Runnable { @Override public void run() { synchronized(this) { try { for (int i = 0; i < 5; i++) { Thread.sleep(100); // 休眠100ms System.out.println(Thread.currentThread().getName() + " loop " + i); } } catch (InterruptedException ie) { } } } } public class Demo1_1 { public static void main(String[] args) { Runnable demo = new MyRunable(); Thread t1 = new Thread(demo, "t1"); Thread t2 = new Thread(demo, "t2"); t1.start(); t2.start(); } }
运行结果:spa
t1 loop 0 t1 loop 1 t1 loop 2 t1 loop 3 t1 loop 4 t2 loop 0 t2 loop 1 t2 loop 2 t2 loop 3 t2 loop 4
结果说明:.net
run()方法中存在synchronized(this)代码块,并且t1和t2都是基于Runnable对象建立的线程。这就意味着,咱们能够将synchronized(this)中的this看做是Runnable对象;所以t1和t2共享demo对象的同步锁。因此,当一个线程运行的时候,另一个线程必须等待“运行中的线程”释放同步锁以后才能运行。特此说明:synchronized(this)中的this是指当前的类对象,即synchronized(this)所在的类对应的当前对象。它的做用是获取“当前对象的同步锁”。
synchronized方法是用synchronized修饰的方法,具体示例这里不给出了,有兴趣的童鞋,能够参照4.1给方法加上synchronized修饰。