Android 线程及线程安全(二)之Synchronized vs Lock
一、Synchronized
synchronized用于修饰方法、静态方法和代码块。
1、修饰代码块
class SaleRunnable implements Runnable{
private int tickets = 100;
@Override
public void run(){
synchronized (this){
while(tickets > 0){
Log.d("TicketsActivity"," 售出票号:"+tickets+" thread.id=="+Thread.currentThread().getId());
try{
//假设售出一张票需要1s
Thread.sleep(1000);
}catch(Exception e){
Log.d("TicketsActivity","error="+e);
}
tickets --;
}
Log.e("TicketsActivity", "run: currentThread.id="+Thread.currentThread().getId());
}
}
}
结果打印如下:
修饰代码块时,锁的作用范围为该类的实例对象,也就是上述的mSaleRunnable,这也解释了为什么312的线程没有进循环,是因为此时的tickets经过311线程的执行变成了0,所以不进循环内。此时被锁的对象是SaleRunnable的实例对象。但当Activity的onCreate()改为以下代码:
@Override
protected void onCreate(Bundle savedInstanceState){
Log.d("TicketsActivity", "onCreate: ");
super.onCreate(savedInstanceState);
new Thread(new SaleRunnable()).start();
new Thread(new SaleRunnable()).start();
}
结果打印如下:
synchronized好像没有起作用,实际不是,synchronized是作用于类的实例对象,但是指针对单一对象,不能作用于实例对象与实例对象之间。上述已经是实例对象与实例对象了。
如果将synchronized 后跟的this改为SaleRunnable.class,如下:
private SaleRunnable mSaleRunnable;
@Override
protected void onCreate(Bundle savedInstanceState){
Log.d("TicketsActivity", "onCreate: ");
super.onCreate(savedInstanceState);
mSaleRunnable = new SaleRunnable();
new Thread(new SaleRunnable()).start();
new Thread(new SaleRunnable()).start();
}
class SaleRunnable implements Runnable{
private int tickets = 10;
@Override
public void run(){
synchronized (SaleRunnable.class){
while(tickets > 0){
Log.d("TicketsActivity"," 售出票号:"+tickets+" thread.id=="+Thread.currentThread().getId());
try{
//假设售出一张票需要1s
Thread.sleep(1000);
}catch(Exception e){
Log.d("TicketsActivity","error="+e);
}
tickets --;
}
Log.e("TicketsActivity", "run: currentThread.id="+Thread.currentThread().getId());
}
}
}
打印结果如下:
这里会进入两次循环,但是不会出现两个线程同时执行的情况,所以还是线程同步的,进入两次循环是因为有两个SaleRunnable的实例化对象,此时锁的作用范围是SaleRunnable类。
2、修饰方法
上述代码修改为:
class SaleRunnable implements Runnable{
private int tickets = 100;
@Override
public void run(){
setTickets();
}
private synchronized void setTickets(){
while(tickets > 0){
Log.d("TicketsActivity"," 售出票号:"+tickets+" thread.id=="+Thread.currentThread().getId());
try{
//假设售出一张票需要1s
Thread.sleep(1000);
}catch(Exception e){
Log.d("TicketsActivity","error="+e);
}
tickets --;
}
Log.e("TicketsActivity", "run: currentThread.id="+Thread.currentThread().getId());
}
}
与修饰代码块的打印结果一致,锁的作用范围为该类的实例对象,且不能作用于实例对象与实例对象之间。此时被称为对象实例锁。
3.修饰静态方法:
static class SaleRunnable implements Runnable{
private static int tickets = 100;
@Override
public void run(){
setTickets();
}
private synchronized static void setTickets(){
while(tickets > 0){
Log.d("TicketsActivity"," 售出票号:"+tickets+" thread.id=="+Thread.currentThread().getId());
try{
//假设售出一张票需要1s
Thread.sleep(1000);
}catch(Exception e){
Log.d("TicketsActivity","error="+e);
}
tickets --;
}
Log.e("TicketsActivity", "run: currentThread.id="+Thread.currentThread().getId());
}
}
修饰静态方法时,锁的作用范围更广,不仅线程执行的是同一个SaleRunnable实例对象时线程同步,当不是同一个SaleRunnable实例对象时也能线程同步,打印结果与修饰方法块时一致。此时被锁的对象是SaleRunnable类。
二、Lock锁的使用
public class MultiThreadStu extends AppCompatActivity {
private SaleRunnable mSaleRunnable;
@Override
protected void onCreate(Bundle savedInstanceState){
Log.d("TicketsActivity", "onCreate: ");
super.onCreate(savedInstanceState);
mSaleRunnable = new SaleRunnable();
new Thread(mSaleRunnable).start();
new Thread(mSaleRunnable).start();
}
class SaleRunnable implements Runnable{
private int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run(){
lock.lock();
while(tickets > 0){
Log.d("TicketsActivity"," 售出票号:"+tickets+" thread.id=="+Thread.currentThread().getId());
try{
//假设售出一张票需要1s
Thread.sleep(1000);
}catch(Exception e){
Log.d("TicketsActivity","error="+e);
}
tickets --;
}
Log.e("TicketsActivity", "run: currentThread.id="+Thread.currentThread().getId());
lock.unlock();
}
}
}
打印结果:
当修改onCreate的代码如下时:
protected void onCreate(Bundle savedInstanceState){
Log.d("TicketsActivity", "onCreate: ");
super.onCreate(savedInstanceState);
mSaleRunnable = new SaleRunnable();
new Thread(new SaleRunnable()).start();
new Thread(new SaleRunnable()).start();
}
打印结果如下:
这说明此时锁的作用范围是SaleRunnable的实例对象,而不是作用于SaleRunnable的实例对象与实例对象之间。