synchronized常见用法解析及示例

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

synchronized常见⽤法解析及⽰例
synchronized作⽤:
保证代码执⾏的原⼦性;
保证可见性(与volatile作⽤相同)
JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步⽅法和同步语句块。

假如再细的分类,synchronized可作⽤于instance变量、object reference(对象引⽤,例如this)、static函数和class literals(类名称字⾯常量)⾝上。

下⾯讨论synchronized⽤到不同地⽅对代码产⽣的影响:
1.
对于⾮static的情况,synchronized是对象级别的,其实质是将synchronized作⽤于对象引⽤(object reference)上,即拿到p1对象锁的线程,对p1的fun()⽅法有同步互斥作⽤,不同的对象之间坚持“和平共处”。

假设P1、P2是同⼀个类的不同对象,这个类中定义了以下⼏种情况的同步块或同步⽅法,P1、P2就都能够调⽤他们。

(1)把synchronized当作函数修饰符时,⽰例代码如下:
public synchronized void method(){
//….
}
这也就是同步⽅法,那这时synchronized锁定的是哪个对象呢?他锁定的是调⽤这个同步⽅法对象。

也就是说,当⼀个对象P1在不同的线程中执⾏这个同步⽅法时,他们之间会形成互斥,达到同步的效果。

但是这个对象所属的Class所产⽣的另⼀对象P2却能够任意调⽤这个被加了synchronized关键字的⽅法。

上边的⽰例代码等同于如下代码:
public void method()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢?他指的就是调⽤这个⽅法的对象,如P1。

可见,同步⽅法实质是将synchronized作⽤于Object Reference。

那个拿到了P1对象锁的线程,才能够调⽤P1的同步⽅法,⽽对P2⽽⾔,P1这个锁和他毫不相⼲,代码也可能在这种情形下摆脱同步机制的控制,造成数据混乱,譬如同时操作静态变量时。

(2).同步块,⽰例代码如下:
public void method(SomeObject so) {
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就能够运⾏他所控制的那段代码。

当有⼀个明确的对象作为锁时,就能够这样写代码,但当没有明确的对象作为锁,只是想让⼀段代码同步时,能够创建⼀个特别的instance变量(它得是个对象)来充当锁:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特别的instance变量
Public void method()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将⽐任何对象都经济。

查看编译后的字节码:⽣成零长度的byte[]对象只需3条操作码,⽽Object lock = new Object()则需要7⾏操作码。

2.
如果⽅法⽤static修饰,synchronized的作⽤范围就是class⼀级的,它对类的所有对象起作⽤。

将synchronized作⽤于static 函数,,⽰例代码如下:
Class Foo
{
public static synchronized void method1() // 同步的static 函数
{
//….
}
public void method2()
{
synchronized(Foo.class) // class literal(类名称字⾯常量)
//请注意,Foo.class也是⼀个对象,类型是Class,在⼀个ClassLoader⾥,它是唯⼀的。

}
}
代码中的method2()⽅法是把class literal作为锁的情况,他和同步的static函数产⽣的效果是相同的,
取得的锁很特别,是当前调⽤这个⽅法的对象所属的类(Class类,⽽不再是由这个Class产⽣的某个具体对象了)。

/kf/201206/134899.html
/j/2008-01-30/200801302324557.shtml
1.
A: synchronized static是某个类的范围,synchronized static cSync{}防⽌多个线程同时访问这个类中的synchronized static ⽅法。

它可以对类的所有对象实例起作⽤。

B: synchronized 是某实例的范围,synchronized isSync(){}防⽌多个线程同时访问这个实例中的synchronized ⽅法。

2.
synchronized⽅法与synchronized代码快的区别
synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是 synchronized methods(){} 便于阅读理解,
⽽synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更⾼效率。

3.synchronized关键字是不能继承的,即,⽗类的synchronized⽅法在⼦类中不是synchronized,必须要重新的显式的声明为synchronized 才⾏。

4.实现同步需要很⼤的系统开销,导致延迟等待,甚⾄可能造成死锁,所以在⾮多线程情况下不要使⽤。

/shipengzhi/articles/2223100.html
代码⽰例:
synchronized使⽤在⽅法中是锁住当前对象,此对象中其它synchrinized⽅法都会阻塞。

synchronized(this)⽰例:
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*2015-4-29*/
public class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
Task task=new Task(true);
Thread readThread=new Thread(task, "Reader");
readThread.start();
TimeUnit.SECONDS.sleep(2);
task.setRead(false);
Thread writeThread=new Thread(task, "Writer");
writeThread.start();
}
}
class Task implements Runnable{
private boolean isRead;
public Task(boolean isRead) {
this.isRead=isRead;
}
private Logger logger=LoggerFactory.getLogger(Task.class);
@Override
public void run() {
try {
if (isRead) {
read();
}else {
write();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void read() throws InterruptedException{
synchronized (this) {
("Enter read() synchronized");
TimeUnit.SECONDS.sleep(20);
("Ready to leave read() synchronized");
}
}
public void write(){
("enter write()");
synchronized (this) {
("enter write() synchronized");
("Ready to leave write() synchronied");
}
("Ready to leave write()");
}
public void setRead(boolean isRead) {
this.isRead = isRead;
}
}
输出:
[2015-04-30 06:30:21,290] [Reader] INFO - Enter read() synchronized
[2015-04-30 06:30:23,290] [Writer] INFO - enter write()
[2015-04-30 06:30:41,290] [Reader] INFO - Ready to leave read() synchronized [2015-04-30 06:30:41,290] [Writer] INFO - enter write() synchronized
[2015-04-30 06:30:41,290] [Writer] INFO - Ready to leave write() synchronied [2015-04-30 06:30:41,290] [Writer] INFO - Ready to leave write() synchronized method_name⽰例:
package thread.synchronizedTest;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SynchronizedMethodTest {
public static void main(String[] args) throws InterruptedException {
Task3 task3 = new Task3(true);
Thread readThread = new Thread(task3, "Reader");
readThread.start();
TimeUnit.SECONDS.sleep(2);
task3.setRead(false);
Thread writeThread = new Thread(task3, "Writer");
writeThread.start();
}
}
class Task3 implements Runnable {
private boolean isRead;
public Task3(boolean isRead) {
this.isRead = isRead;
}
private Logger logger = LoggerFactory.getLogger(Task3.class);
@Override
public void run() {
try {
if (isRead) {
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void read() throws InterruptedException {
("Enter read() synchronized");
TimeUnit.SECONDS.sleep(20);
("Ready to leave read() synchronized");
}
public synchronized void write() {
("enter write()");
// synchronized (this) {
("enter write() synchronized");
("Ready to leave write() synchronied");
// }
("Ready to leave write()");
}
public void setRead(boolean isRead) {
this.isRead = isRead;
}
}
输出:
[2015-04-30 07:02:04,583] [Reader] INFO - Enter read() synchronized
[2015-04-30 07:02:24,583] [Reader] INFO - Ready to leave read() synchronized
[2015-04-30 07:02:24,583] [Writer] INFO - enter write()
[2015-04-30 07:02:24,583] [Writer] INFO - enter write() synchronized
[2015-04-30 07:02:24,583] [Writer] INFO - Ready to leave write() synchronied
[2015-04-30 07:02:24,583] [Writer] INFO - Ready to leave write()
使⽤⼀个声明的变量作为锁时,可以让锁的粒度更⼩,如果合理使⽤会提⾼程序执⾏效率:package thread.synchronizedTest;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*2015-4-29*/
public class SynchronizedLockObjectTest {
public static void main(String[] args) throws InterruptedException {
Task2 task2=new Task2(true);
Thread readThread=new Thread(task2, "Reader");
readThread.start();
TimeUnit.SECONDS.sleep(2);
task2.setRead(false);
Thread writeThread=new Thread(task2, "Writer");
writeThread.start();
}
}
class Task2 implements Runnable{
private byte[] readLock = new byte[0]; // 特别的instance变量
private byte[] writeLock = new byte[0]; // 特别的instance变量
private boolean isRead;
public Task2(boolean isRead) {
this.isRead=isRead;
}
private Logger logger=LoggerFactory.getLogger(Task2.class);
@Override
public void run() {
try {
write();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void read() throws InterruptedException{
synchronized (readLock) {
("Enter read() synchronized");
TimeUnit.SECONDS.sleep(20);
("Ready to leave read() synchronized");
}
}
public void write(){
("enter write()");
synchronized (writeLock) {
("enter write() synchronized");
("Ready to leave write() synchronied");
}
("Ready to leave write()");
}
public void setRead(boolean isRead) {
this.isRead = isRead;
}
}
输出:
[2015-04-30 06:37:20,148] [Reader] INFO - Enter read() synchronized
[2015-04-30 06:37:22,148] [Writer] INFO - enter write()
[2015-04-30 06:37:22,148] [Writer] INFO - enter write() synchronized
[2015-04-30 06:37:22,148] [Writer] INFO - Ready to leave write() synchronied
[2015-04-30 06:37:22,148] [Writer] INFO - Ready to leave write()
[2015-04-30 06:37:40,149] [Reader] INFO - Ready to leave read() synchronized
synchronized(字段)和synchronized(当前对象)在⼀个实例中同时存在时,两个⽅法会同时执⾏,因为synchronized持有的对象不同,⼀个是当前对象,⼀个字段对象:
package thread.synchronizedTest;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SychronizedLockFieldorMethod {
public static void main(String[] args) throws InterruptedException {
Task4 task4 = new Task4(true);
Thread readThread = new Thread(task4, "Reader");
readThread.start();
TimeUnit.SECONDS.sleep(2);
task4.setRead(false);
Thread writeThread = new Thread(task4, "Writer");
writeThread.start();
}
}
class Task4 implements Runnable {
private byte[] readLock = new byte[0]; // 特别的instance变量
private byte[] writeLock = new byte[0]; // 特别的instance变量
private boolean isRead;
public Task4(boolean isRead) {
this.isRead = isRead;
}
private Logger logger = LoggerFactory.getLogger(Task4.class);
@Override
public void run() {
try {
if (isRead) {
read();
} else {
write();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void read() throws InterruptedException {
// synchronized (readLock) {
("Enter read() synchronized");
TimeUnit.SECONDS.sleep(20);
("Ready to leave read() synchronized");
// }
}
public void write() {
("enter write()");
synchronized (writeLock) {
("enter write() synchronized");
("Ready to leave write() synchronied");
}
("Ready to leave write()");
}
public void setRead(boolean isRead) {
this.isRead = isRead;
}
}
输出:
[2015-04-30 06:54:41,294] [Reader] INFO - Enter read() synchronized
[2015-04-30 06:54:43,294] [Writer] INFO - enter write()
[2015-04-30 06:54:43,294] [Writer] INFO - enter write() synchronized
[2015-04-30 06:54:43,294] [Writer] INFO - Ready to leave write() synchronied
[2015-04-30 06:54:43,294] [Writer] INFO - Ready to leave write()
[2015-04-30 06:55:01,295] [Reader] INFO - Ready to leave read() synchronized
synchronized如果是⼀个⼊参,则不能起到同步的作⽤。

因为这种场景和synchronized(this)的原理是⼀样的。

但每次⼊参都是不同的对象,这些不同的对象不能形成互斥
import java.util.concurrent.TimeUnit;
public class SynchronizedParameter implements Runnable {
private static Biz biz = new Biz();
private String key;
public SynchronizedParameter(String key) {
this.key = key;
}
public static void main(String[] args) throws InterruptedException {
String key1 = "key1";
Thread thread1 = new Thread(new SynchronizedParameter(key1), key1);
String key2 = "key2";
Thread thread2 = new Thread(new SynchronizedParameter(key2), key2);
Thread thread2_bak = new Thread(new SynchronizedParameter(key2), key2 + "bak");
thread1.start();
thread2.start();
thread2_bak.start();
thread1.join();
thread2.join();
thread2_bak.join();
System.out.println(Thread.currentThread() + "end...");
}
@Override
public void run() {
biz.handle(key);
}
public void setKey(String key) {
this.key = key;
}
}
class Biz {
public void handle(String key) {
System.out.println(Thread.currentThread() + " " + key + " " + System.currentTimeMillis());
synchronized (key) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread() + " " + key + " " + System.currentTimeMillis()); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Thread[key1,5,main] key1 1476842469690
Thread[key2,5,main] key2 1476842469691
Thread[key2bak,5,main] key2 1476842469695
Thread[key2,5,main] key2 1476842470691
Thread[key1,5,main] key1 1476842470691
Thread[key2bak,5,main] key2 1476842471691
Thread[main,5,main]end...。

相关文档
最新文档