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