解决线程安全问题笔记

同步技术的原理

使用一个锁对象,这个锁对象叫同步锁,也叫对象锁,也可以叫对象监视器。在同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去同步。同步保证了只能有一个先线程在同步中执行共享数据,进而保证了安全,但程序频繁的判断锁,获取锁,释放锁,程序的效率会降低。例子如下:

// 同步技术的格式
synchronize(同步锁) {
	需要同步操作的对象
}
public class Demo{
    public static void main(String[] args) {
//        创建接口实现类对象
        RunnableImpl ru  = new RunnableImpl();
//        创建四个线程
        Thread th1 = new Thread(ru);
        Thread th2 = new Thread(ru);
        Thread th3 = new Thread(ru);
        Thread th4 = new Thread(ru);
//        启动线程
        th1.start();
        th2.start();
        th3.start();
        th4.start();


    }


}
public class RunnableImpl implements Runnable{
// 定义一个多线程的票源
    private int ticket = 50;
//	设置了一个Object的锁对象    
    Object obj = new Object();
    // 设置线程任务:卖票
    @Override
    public void run() {
        while(true){
//			同步代码块        
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                    // 解决线程安全问题出现的概率,让程序睡眠
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
                    ticket--;
            }
            }
        }
    }
}

同步方法

同步方法:使用synchronize修饰的方法,保证线程1执行时,其他的线程只能在方法外等待。同步方法默认的锁对象就是线程的实现类对象(this)。

public synchronize void method () {
	可能会产生线程安全问题的代码块
}

使用步骤:

  • 1.把访问的共享数据的代码抽取出来,放到一个方法中
  • 2.在方法上添加synchronize的修饰符
public class Demo{
    public static void main(String[] args) {
//        创建接口实现类对象
        RunnableImpl ru  = new RunnableImpl();
//        创建四个线程
        Thread th1 = new Thread(ru);
        Thread th2 = new Thread(ru);
        Thread th3 = new Thread(ru);
        Thread th4 = new Thread(ru);
//        启动线程
        th1.start();
        th2.start();
        th3.start();
        th4.start();


    }
}
// 输出结果
Thread-0还剩50张票
Thread-0还剩49张票
Thread-0还剩48张票
Thread-0还剩47张票
Thread-0还剩46张票
Thread-2还剩45张票
Thread-2还剩44张票
Thread-2还剩43张票
Thread-2还剩42张票
Thread-2还剩41张票
Thread-2还剩40张票
Thread-2还剩39张票
Thread-2还剩38张票
Thread-2还剩37张票
Thread-2还剩36张票
Thread-2还剩35张票
Thread-2还剩34张票
Thread-2还剩33张票
Thread-2还剩32张票
Thread-2还剩31张票
Thread-2还剩30张票
Thread-2还剩29张票
Thread-2还剩28张票
Thread-2还剩27张票
Thread-2还剩26张票
Thread-2还剩25张票
Thread-2还剩24张票
Thread-2还剩23张票
Thread-2还剩22张票
Thread-2还剩21张票
Thread-2还剩20张票
Thread-2还剩19张票
Thread-2还剩18张票
Thread-2还剩17张票
Thread-2还剩16张票
Thread-2还剩15张票
Thread-2还剩14张票
Thread-2还剩13张票
Thread-2还剩12张票
Thread-2还剩11张票
Thread-2还剩10张票
Thread-2还剩9张票
Thread-2还剩8张票
Thread-2还剩7张票
Thread-2还剩6张票
Thread-2还剩5张票
Thread-2还剩4张票
Thread-2还剩3张票
Thread-2还剩2张票
Thread-2还剩1张票
public class RunnableImpl implements Runnable{
    private int ticket = 50;
    Object obj = new Object();
    @Override
    public void run() {
        while(true){
            method();
        }
    }
    // 带有synchronize修饰符的方法
    public synchronized void method () {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
            ticket--;
        }
    }
}

静态同步方法

静态同步方法的锁对象是线程实现类的class属性(Runnable.class)
格式如下:

public static synchronize void method () {
	可能会产生线程安全问题的代码块
}
public class RunnableImpl implements Runnable{
    private static int ticket = 50;
    Object obj = new Object();
    @Override
    public void run() {
        while(true){
            method();
        }
    }
    public static synchronized void method () {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
            ticket--;
        }
    }
}
public class Demo{
    public static void main(String[] args) {
//        创建接口实现类对象
        RunnableImpl ru  = new RunnableImpl();
//        创建四个线程
        Thread th1 = new Thread(ru);
        Thread th2 = new Thread(ru);
        Thread th3 = new Thread(ru);
        Thread th4 = new Thread(ru);
//        启动线程
        th1.start();
        th2.start();
        th3.start();
        th4.start();


    }


}

Lock锁

java.util.concurrent.locks.Lock机制提供了比synchronize和synchronize方法更广泛的锁定操作,同步代码块和同步方法有的功能Lock锁都有,除此之外更强大,体现在面对对象。
Lock锁又称同步锁,加锁和释放锁方法化,Lock接口的方法,如下:

  • public void lock():获取锁
  • public void unlock():释放锁
    使用步骤:
  • 1.在成员位置创建ReentrantLock对象
  • 2.在可能出现安全问题的代码前调用Lock()方法,获取锁。
  • 3.在可能出现安全问题的代码后调用unlock()方法,释放锁
    例子如下:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RunnableImpl implements Runnable{
    private int ticket = 50;
    Object obj = new Object();
    Lock l = new ReentrantLock();
    @Override
    public void run() {
        while(true){
            l.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally {
                    l.unlock();
                }

            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值