Java多线程--synchronized修饰普通方法和修饰静态方法的区别
作者:互联网
初始化一个对象时,会自动生成一个与该对象对应的对象锁,被synchronized 修饰的方法就得依靠对象锁工作。当多线程同时访问某个被synchronized修饰的方法时,一旦某个进程抢得对象锁之后,其他的进程只有排队对待。
一、synchronized修饰普通方法
初始化一个对象时,会自动生成一个与该对象对应的对象锁,被synchronized 修饰的方法就得依靠对象锁工作。当多线程同时访问某个被synchronized修饰的方法时,一旦某个进程抢得对象锁之后,其他的进程只有排队对待。
例如,Person类里有2个被synchronized 修饰的方法,…还是看代码吧:
public class Person { public synchronized void eatApple() { Log.d("TAG", "eatApple begin at:" + System.currentTimeMillis()); SystemClock.sleep(3000); Log.d("TAG", "eatApple end at:" + System.currentTimeMillis()); } public synchronized void eatOrange() { for (int i = 0; i < 10; i++) { Log.d("TAG", "eatOrange is running"); SystemClock.sleep(200); } } }
public class MainActivity extends AppCompatActivity { Person person = new Person(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); thread1.start(); thread2.start(); } Thread thread1 = new Thread(new Runnable() { @Override public void run() { person.eatApple(); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { person.eatOrange(); } }); }
运行结果:
12-14 16:26:48.243 14867-14920/com.example.shengqf.myapplication D/TAG: eatApple begin at:1513240008242 12-14 16:26:51.244 14867-14920/com.example.shengqf.myapplication D/TAG: eatApple end at:1513240011243 12-14 16:26:51.246 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:51.447 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:51.648 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:51.848 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:52.049 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:52.250 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:52.451 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:52.652 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:52.853 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:26:53.055 14867-14921/com.example.shengqf.myapplication D/TAG: eatOrange is running
结论:因为thread1中的eatApple()方法和thread2中的eatOrange()方法都是通过person对象调用的,他们用的是同一个对象锁,互斥。所以,thread2一直等到thread1中的eatApple()方法执行完释放了对象锁后才开始执行其eatOrange()方法。
现在将上面thread2代码改一下:
Thread thread2 = new Thread(new Runnable() { @Override public void run() { Person person2 = new Person(); person2.eatOrange(); } });
再运行,结果:
12-14 16:43:05.011 16294-16320/com.example.shengqf.myapplication D/TAG: eatApple begin at:1513240985011 12-14 16:43:05.011 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:05.211 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:05.412 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:05.612 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:05.813 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:06.014 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:06.215 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:06.416 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:06.617 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:06.818 16294-16321/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-14 16:43:08.012 16294-16320/com.example.shengqf.myapplication D/TAG: eatApple end at:1513240988011
因为thread1中的eatApple()方法是通过person对象调用的,而thread2中的eatOrange()方法是通过person2对象调用的,他们用的是两个不同的对象锁,并不互斥。所以,thread2中的eatOrange()方法是和thread1中的eatApple()方法同时进行的。
结论:使用“同一个对象”去调用其被synchronized 修饰的普通方法才互斥。
上面的Person类等效于:
public class Person{ public void eatApple() { synchronized(Person.this){ Log.d("TAG", "eatApple begin at:" + System.currentTimeMillis()); SystemClock.sleep(3000); Log.d("TAG", "eatApple end at:" + System.currentTimeMillis()); } } public void eatOrange() { synchronized (Person.this) { for (int i = 0; i < 10; i++) { Log.d("TAG", "eatOrange is running"); SystemClock.sleep(200); } } } }
二、synchronized修饰静态方法
直接看代码:
public class Person { public synchronized static void eatApple() { Log.d("TAG", "eatApple begin at:" + System.currentTimeMillis()); SystemClock.sleep(3000); Log.d("TAG", "eatApple end at:" + System.currentTimeMillis()); } public synchronized static void eatOrange() { for (int i = 0; i < 10; i++) { Log.d("TAG", "eatOrange is running"); SystemClock.sleep(200); } } }
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); thread1.start(); thread2.start(); } Thread thread1 = new Thread(new Runnable() { @Override public void run() { Person.eatApple(); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { Person.eatOrange(); } }); }
运行结果:
12-15 09:09:24.378 31625-31912/com.example.shengqf.myapplication D/TAG: eatApple begin at:1513300164378 12-15 09:09:27.379 31625-31912/com.example.shengqf.myapplication D/TAG: eatApple end at:1513300167379 12-15 09:09:27.381 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:27.582 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:27.783 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:27.984 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:28.184 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:28.385 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:28.585 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:28.786 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:28.986 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:09:29.188 31625-31913/com.example.shengqf.myapplication D/TAG: eatOrange is running
现在将thread1和thread2代码改为:
Thread thread1 = new Thread(new Runnable() { @Override public void run() { Person person1 = new Person(); person1.eatApple(); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { Person person2 = new Person(); person2.eatOrange(); } });
再运行结果:
12-15 09:12:38.316 32353-32378/com.example.shengqf.myapplication D/TAG: eatApple begin at:1513300358316 12-15 09:12:41.317 32353-32378/com.example.shengqf.myapplication D/TAG: eatApple end at:1513300361317 12-15 09:12:41.320 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:41.521 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:41.721 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:41.922 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:42.123 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:42.324 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:42.525 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:42.727 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:42.928 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running 12-15 09:12:43.129 32353-32379/com.example.shengqf.myapplication D/TAG: eatOrange is running
因为eatApple()和eatOrange()方法都是Person类里的静态方法,且被synchronized修饰,所以这两个方法都是靠唯一的Person类锁工作,所以无论是通过Person类名调用还是new不同的person对象调用,两个方法都是互斥的。
结论:被synchronized 修饰的静态方法要靠类锁工作。当多线程同时访问某个被synchronized修饰的静态方法时,一旦某个进程抢得该类的类锁之后,其他的进程只有排队对待。
上面的Person代码等效于:
public class Person { public static void eatApple() { synchronized(Person.class){ Log.d("TAG", "eatApple begin at:" + System.currentTimeMillis()); SystemClock.sleep(3000); Log.d("TAG", "eatApple end at:" + System.currentTimeMillis()); } } public static void eatOrange() { synchronized(Person.class){ for (int i = 0; i < 10; i++) { Log.d("TAG", "eatOrange is running"); SystemClock.sleep(200); } } } }
标签:12,Java,shengqf,TAG,eatOrange,修饰,多线程,com,myapplication 来源: https://blog.51cto.com/u_7692005/2969175