多线程基础知识总结二---线程安全

线程安全问题

三种解决方案

在这里插入图片描述

同步代码块

多线程售票程序

/*
 * 卖票案例出现了线程安全问题
 * 卖出了不存在的票和重复的票
 * 解决线程安全问题的一种方案:使用同步代码块
 * 格式:
 *    synchronized(锁对象){
 *       可能会出现线程安全的代码(访问了共享数据的代码)
 *    }
 * 注意:
 *    通过代码块中的锁对象,可以使用任意的对象
 *    但是必须保证多个线程使用的锁对象是同一个
 *    锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行
 */
public class SynCodeBlock implements Runnable {
	// 定义一个多线程共享的票源
	private Integer ticket = 100;
	Object obj = new Object();

	@Override
	public void run() {
		while (true) { // 此处设置ticket>=1的话 三个进程可能都满足此条件
			// 提高安全问题出现的概率,让程序睡眠
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized (obj) {
				if (ticket >= 1) {
					System.out.println(Thread.currentThread().getName()
							+ "正在售卖第" + (100 - (--ticket)) + "张票");
				}
			}
		}
		// TODO Auto-generated method stub
	}
}

执行多线程程序

public class SynCodeBlockMain {	
	public static void main(String []args){
		SynCodeBlock run=new SynCodeBlock();
	    Thread t1=new Thread(run);
	    Thread t2=new Thread(run);
	    Thread t3=new Thread(run);
	    t1.start();
	    t2.start();
	    t3.start();
	}
}

同步方法

多线程售票程序

public class SynMethod implements Runnable {
	private Integer ticket=100;
	Object obj=new Object();
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			showTicket_1();
		}
	}
	//同步方法一
	public synchronized void showTicket(){
		if(ticket>=1){
			
			System.out.println(Thread.currentThread().getName()+"正在售卖第"+(100-(--ticket))+"张票");	
		}
	}
	//同步方法二
	public void showTicket_1(){
		synchronized(this){
			if(ticket>=1){
				System.out.println(Thread.currentThread().getName()+"正在售卖的第"+(100-(--ticket))+"张票");
			}
		}
	}
}

执行多线程程序

/*
 * 模拟卖票的案例
 * 创建3个线程,同时开启,对共享的票进行出售
 */
public class SynMethodMain {
	public static void main(String []args){
		SynMethod run=new SynMethod();
		Thread t1=new Thread(run);
		Thread t2=new Thread(run);
		Thread t3=new Thread(run);
		t1.start();
		t2.start();
		t3.start();
	}
}

静态同步方法

多线程售票程序

public class SynStatic implements Runnable {
	private static Integer ticket = 100;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
		    try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			showTicket_1();
		}
	}
	//方法一
	public synchronized static void showTicket() {
		if (ticket >= 1) {
			System.out.println(Thread.currentThread().getName() + "正在售卖第"
					+ (100 - (--ticket)) + "张票");
		}
	}	
	/*方法二 
	静态同步方法
	锁对象是谁?
	不能是this
	this是创建对象后产生的,静态方法优先于对象
	静态方法的锁对象是本类的class属性-->class文件对象(反射)
	*/
	public static void showTicket_1(){
		synchronized(Runnable.class){
			if (ticket >= 1) {
				System.out.println(Thread.currentThread().getName() + "正在售卖d第"
						+ (100 - (--ticket)) + "张票");
			}
		}		
	}
}

执行多线程程序

/*
 Java.util.concurrent.locks.Lock接口
 Lock实现提供了比使用synchronized方法和语句可获得更广泛的锁定操作。
 Lock接口中的方法:
 Void lock()  获取锁
 Void unlock() 释放锁
 Java.util.concurrent.locks.ReentrantLock lock接口
 使用步骤:
 1、	在成员位置创建一个ReentrantLock对象
 2、	在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取锁
 3、	在可能会出现安全问题的代码后调用Lock接口中的方法Lock释放锁
 */
public class SynStaticMain {
    public static void main(String []args){
    	SynStatic  run=new SynStatic();
    	Thread t1=new Thread(run);
    	Thread t2=new Thread(run);
    	Thread t3=new Thread(run);
    	t1.start();
    	t2.start();
    	t3.start();
    }
}

Lock锁

多线程售票程序

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockRunnable implements Runnable{
	private Integer ticket=100;
	// 1、在成员位置创建一个ReentrantLock对象
	Lock lock=new ReentrantLock();
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
		    // 2、在可能出现安全问题的代码前调用lock接口中的方法lock获取锁
			lock.lock();
			if (ticket > =1) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally { // 无论是否会出现异常 锁都会被释放掉
					System.out.println(Thread.currentThread().getName()+"正在售卖第"+(100-(--ticket))+"张票");
					// 3、在可能出现安全问题的代码后调用Lock接口中的方法unlock释放锁
					lock.unlock();
				}
			}
		}
	}
}

执行多线程程序

public class LockMain {
	public static void main(String []args){
		LockRunnable run=new LockRunnable();
		Thread t1=new Thread(run);
		Thread t2=new Thread(run);
		Thread t3=new Thread(run);
		t1.start();
		t2.start();
		t3.start();
	} 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值