49--多线程(八)

Lock(锁)

1.从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同 步锁对象来实现同步。同步锁使用Lock对象充当。
2.java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的 工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象 加锁,线程开始访问共享资源之前应先获得Lock对象。
3.ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和 内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以 显式加锁、释放锁。
实例:

package com.qwy13;

import java.util.concurrent.locks.ReentrantLock;

class Window extends Thread {
    
    
	private static int ticket = 10;
	//1.创建锁对象:注意需要加static
	private static ReentrantLock reet= new ReentrantLock();
	@Override
	public void run() {
    
    
		//为了能将票卖完,这里多循环了
		for(int i=0;i<1000;i++){
    
    
			sell();
		}

	}
	
	private  void sell() {
    
    

		try {
    
    
			//2.显示的加锁
			reet.lock();
			if (ticket > 0) {
    
    
				try {
    
    
					Thread.sleep(100);
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "卖出票号:" + ticket--);
			}
		} finally{
    
    
			//显示释放锁
			reet.unlock();
		}

	}
}

public class TestTick {
    
    
	public static void main(String[] args) {
    
    
		// 创建三个线程对象,表示三个窗口
		Window w1 = new Window();
		Window w2 = new Window();
		Window w3 = new Window();
		// 给三个窗口起名(设置线程名称)
		w1.setName("窗口A");
		w2.setName("窗口B");
		w3.setName("窗口C");
		// 启动线程
		w1.start();
		w2.start();
		w3.start();

	}
}

可能的运行结果:
窗口A卖出票号:10
窗口A卖出票号:9
窗口A卖出票号:8
窗口A卖出票号:7
窗口B卖出票号:6
窗口C卖出票号:5
窗口C卖出票号:4
窗口C卖出票号:3
窗口A卖出票号:2
窗口A卖出票号:1

实例:

package com.qwy14;

import java.util.concurrent.locks.ReentrantLock;

class Window implements Runnable {
    
    

	private int ticket = 10;
	private ReentrantLock lock= new ReentrantLock();
	@Override
	public void run() {
    
    
		while(true){
    
    
			try {
    
    
				lock.lock();//手动加锁
				if(ticket>0){
    
    
					try {
    
    
						Thread.currentThread().sleep(100);
					} catch (InterruptedException e) {
    
    
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "卖出票号:" + ticket--);
				}else{
    
    
					break;
				}
			} finally {
    
    
				lock.unlock();//手动释放锁
			}
		}

	}
	

}

public class TestTickit {
    
    
	public static void main(String[] args) {
    
    
		// 创建Runnable接口实例
		Window w1 = new Window();
		// 创建三个线程表示三个窗口
		Thread t1 = new Thread(w1);
		Thread t2 = new Thread(w1);
		Thread t3 = new Thread(w1);
		// 给线程起名
		t1.setName("窗口A");
		t2.setName("窗口B");
		t3.setName("窗口C");

		// 启动线程
		t1.start();
		t2.start();
		t3.start();

	}
}

运行的可能结果:
窗口A卖出票号:10
窗口A卖出票号:9
窗口A卖出票号:8
窗口C卖出票号:7
窗口C卖出票号:6
窗口C卖出票号:5
窗口B卖出票号:4
窗口B卖出票号:3
窗口A卖出票号:2
窗口A卖出票号:1

synchronized 与 Lock 的对比

相同:二者都可以解决线程安全问题
不同:1.synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())
2. Lock只有代码块锁,synchronized有代码块锁和方法锁
3.使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有 更好的扩展性(提供更多的子类)

实例

银行有一个账户。 有夫妻两个人分别向同一个账户存3000元,每次存1000,存3次。每次存完打 印账户余额。
实例1:继承Thread类同步方法方式

package com.qwy15;
class Account{
    
    
	private double balance;
	public Account() {
    
    
		// TODO Auto-generated constructor stub
	}
	public Account(double balance) {
    
    
		this.balance = balance;
	}
	public synchronized void deposit(double momey){
    
    
		if(momey>0){
    
    
			 try {
    
    
	                Thread.sleep(10);
	            } catch (InterruptedException e) {
    
    
	                e.printStackTrace();
	            }
			balance+=momey;
			System.out.println(Thread.currentThread().getName()+":存钱成功,余额:"+balance);
		}
	}
	
}

class Customer extends Thread{
    
    
	private Account accout;
	public Customer(Account accout) {
    
    
		super();
		this.accout = accout;
	}

	@Override
	public void run() {
    
    
		for(int i=0;i<3;i++){
    
    
			accout.deposit(1000);
		}
		
	}
	
}
public class AccountTest {
    
    
	public static void main(String[] args) {
    
    
		Account accout= new Account(0);
		Customer c1= new Customer(accout);
		Customer c2= new Customer(accout);
		
		
		c1.setName("丈夫");
		c2.setName("妻子");
		c1.start();
		c2.start();
	}
}


可能运行结果:
丈夫:存钱成功,余额:1000.0
妻子:存钱成功,余额:2000.0
妻子:存钱成功,余额:3000.0
妻子:存钱成功,余额:4000.0
丈夫:存钱成功,余额:5000.0
丈夫:存钱成功,余额:6000.0

实例2: 使用Lock方式

package com.qwy16;

import java.util.concurrent.locks.ReentrantLock;

class Account{
    
    
	private double balance;
	private ReentrantLock lock= new ReentrantLock();
	public Account() {
    
    
		// TODO Auto-generated constructor stub
	}
	public Account(double balance) {
    
    
		this.balance = balance;
	}
	public  void deposit(double momey){
    
    
		try {
    
    
			lock.lock();
			if(momey>0){
    
    
				 try {
    
    
		                Thread.sleep(10);
		            } catch (InterruptedException e) {
    
    
		                e.printStackTrace();
		            }
				balance+=momey;
				System.out.println(Thread.currentThread().getName()+":存钱成功,余额:"+balance);
			}
		} finally {
    
    
			lock.unlock();
		}
	}
	
}

class Customer extends Thread{
    
    
	private Account accout;
	public Customer(Account accout) {
    
    
		super();
		this.accout = accout;
	}

	@Override
	public void run() {
    
    
		for(int i=0;i<3;i++){
    
    
			accout.deposit(1000);
		}
		
	}
	
}
public class AccountTest {
    
    
	public static void main(String[] args) {
    
    
		Account accout= new Account(0);
		Customer c1= new Customer(accout);
		Customer c2= new Customer(accout);
		c1.setName("丈夫");
		c2.setName("妻子");
		c1.start();
		c2.start();
	}
}

可能的运行结果;
妻子:存钱成功,余额:1000.0
妻子:存钱成功,余额:2000.0
丈夫:存钱成功,余额:3000.0
丈夫:存钱成功,余额:4000.0
丈夫:存钱成功,余额:5000.0
妻子:存钱成功,余额:6000.0

未完待续
=============================================================================================
如有不妥之处,欢迎大家给予批评指出,如果对您有帮助,给留下个小赞赞哦
==============================================================================================

猜你喜欢

转载自blog.csdn.net/qwy715229258163/article/details/114948063