网上一搜索synchronized,资料大把大把,因此也不展开来讲,怕说多错多。简单说说个人理解和用法。java
synchronized是Java中的关键字,是一种同步锁。一般能够用来修饰某个方法,或者某个代码块。线程
我通常用来修饰代码块,感受会更加灵活。先上个例子:code
public class Task implements Runnable{ private static final Object LOCK = new Object(); public void run(){ long threadId = Thread.currentThread().getId(); System.out.println(threadId + " 等待执行"); synchronized (LOCK) { try { System.out.println(threadId + " 执行中"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadId + " 执行结束"); } } }
首先咱们定义了一个常量LOCK,执行到这个synchronized 代码块的时候,都会先检查是否得到LOCK的使用权。对象
因为LOCK是全局的常量,因此全部线程拿到的都是同一个LOCK对象,因此全部线程在到这里的时候,都须要排队等LOCK。get
即下面例子全部的调用,都会等待。PS.你也能够去掉synchronized关键词来看下另一种执行结果。同步
public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); for (int i=0; i<10; i++) { service.execute(new Task()); } }
若是LOCK的定义改成下面这种。io
private Object LOCK = new Object();
再执行上述的main方法,会发现,代码块里面的内容再也不等待了。当一个线程执行时,另一个线程也开始执行了。class
为何呢?由于每一个线程的LOCK再也不是同一个对象实例了。如今每一个LOCK都只属于它们的类实例。thread
这时,咱们能够这么改。搜索
public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); Task task = new Task(); for (int i=0; i<10; i++) { service.execute(task); } }
对于每一个线程来讲,LOCK都是同一个锁,因此线程间会进行等待。
总结一句:synchronized修饰代码块的时候,可让使用了同一个锁对象实例的多个线程进行排队等待执行。
再补充一个,使用synchronized的时候,常常要使用到双重检查。仍是直接举例子吧。
假设咱们有个将任务修改成完成的功能,修改成完成状态以后,还要通知发任务的用户。若是不使用同步锁进行控制,多人触发同一个任务的完成操做时,可能会出现屡次通知同一个用户的状况。这时,咱们可使用synchronized来防止这个状况。代码大概是这样的。
public void completeTask(long taskId) { Task task = Task.get(taskId); if(task!=null && task.hasCompleted()) { return; } synchronized (task) { task = Task.get(taskId); if(task!=null && task.hasCompleted()) { return; } Task.complete(task); NoticeUtil.noticeTaskComplete(task.getPublisher()); } }
一开始,咱们获取了一个task实例,这里,咱们必须保证对于相同taskId的task必须是同一个实例对象,synchronized才会有效。
拿到task以后,咱们先检查task是否存在,而且是否已完成。
而后会进行排队,排队以后,咱们会再次进行上述检查。这两次检查,就是双重功能检查的意思。能够避免出现多个线程重复执行某段代码。假设没有第二次检查,则排队线程得到锁的时候,同样会有“通知用户”的行为。
表达能力有限,不知道上述内容有没有把我表达的意思说清楚。但愿对看到本文的你有所帮助:-)。