synchronized之同步代码块和同步方法

1.synchronized同步关键字
这里涉及到多个线程对共享资源进行处理,这里就必须要给线程“排队”,使用的关键字是synchronized(同步),在程序中,给对共享资源进行处理的代码部分(整个方法或代码块)添加此关键字。相当于给代码块加锁,取得钥匙的线程对资源操作,完成后将钥匙交予其他线程,这保证了同一个资源某一时间内只有一个线程可以对其修改等操作。

同步代码块

synchronized(lock){
    
    
操作共享资源代码块
}

lock是一个锁对象,它是同步代码块的关键。当线程执行同步代码块时,首先会检查锁对象的标志位,默认情况下标志位为1,此时线程会执行同步代码块,同时将锁对象的标志位置为0,当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代码。循环往复,直到共享资源被处理完为止。这个过程就好比一个公用电话亭,只有前一个人打完电话出来后,后面的人才可以打。

注意:

  1. 同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是唯一的。“任意”说的是共享锁对象的类型。所以,锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象,这样每个线程都会有一个不同的锁,每个锁都有自己的标志位。线程之间便不能产生同步的效果。
public void run(){
    
     
   Object lock = new Object(); 
    //代码 
    synchronized(lock){
    
    //锁失去了意义 
         //对共享资源处理代码 
    } 
    //代码 
} 
  1. 注意细分锁。可以有多个锁对象,对不同的资源“上锁”
class A{
    
     
     private Object lock1 = new Object(); 
     private Object lock2 = new Object(); 
     
     void f(){
    
     
           synchronized(lock1){
    
     
                 //访问资源P 
           } 
     } 

     void g(){
    
     
           synchronized(lock2){
    
     
                 //访问资源Q 
           } 
     } 
} 

下面来一个买票的例子:

//定义Ticket1类继承Runnable接口
class Ticket1 implements Runnable {
    
    
	private int tickets = 10; // 定义变量tickets,并赋值10
	**Object lock = new Object(); // 定义任意一个对象,用作同步代码块的锁**
	public void run() {
    
    
		while (true) {
    
    
			**synchronized (lock) {
    
     // 定义同步代码块**
				try {
    
    
					Thread.sleep(10); // 经过的线程休眠10毫秒
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
				if (tickets > 0) {
    
    
					System.out.println(Thread.currentThread().getName()
							+ "---卖出的票" + tickets--);
				} else {
    
     // 如果 tickets小于0,跳出循环
					break;
				}
			}
		}
	}
}
public class Example {
    
    
	public static void main(String[] args) {
    
    
		Ticket1 ticket = new Ticket1(); // 创建Ticket1对象
		// 创建并开启四个线程
		new Thread(ticket, "线程一").start();
		new Thread(ticket, "线程二").start();
		new Thread(ticket, "线程三").start();
		new Thread(ticket, "线程四").start();
	}
}

运行结果:

同步方法

格式:synchronized返回值类型 方法名([参数1, … ] ){}
被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,直到当前线程访问完毕后,其他线程才有机会执行方法。

// 定义Ticket1类实现Runnable接口
class Ticket1 implements Runnable {
    
    
	private int tickets = 10;
	public void run() {
    
    
		while (true) {
    
    
			saleTicket(); // 调用售票方法
			if (tickets <= 0) {
    
     
				break;
			}
		}
	}
    // 定义一个同步方法saleTicket()
	private synchronized void saleTicket() {
    
    
		if (tickets > 0) {
    
    
			try {
    
    
				Thread.sleep(10); // 经过的线程休眠10毫秒
			} catch (InterruptedException e) {
    
    
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "---卖出的票"
					+ tickets--);
		}
	}
}
public class Example {
    
    
	public static void main(String[] args) {
    
    
		Ticket1 ticket = new Ticket1(); // 创建Ticket1对象
         // 创建并开启四个线程
		new Thread(ticket,"线程一").start();
		new Thread(ticket,"线程二").start();
		new Thread(ticket,"线程三").start();
		new Thread(ticket,"线程四").start();
	}
}


猜你喜欢

转载自blog.csdn.net/xun08042/article/details/113844343
今日推荐