线程--同步和安全

线程的同步与安全:
在很多情况下,我们都会遇到线程的安全与同步问题,例如下面网上售票的系统:
如果不对不加线程锁的话,会出现不同的窗口买出重票,而现实生活中例如(1-100)每个票就一张总共100张,不可能重复.

这里有线程安全同步的三个方法:
1.同步代码块:
Object obj = new Object();
synchronized (obj) {}
这里我自己要明白为啥这样写,
首先object类说有类的父类,这里就是用obj来代替所有的对象
二者,下面才是重要的,就是锁住你觉得会发生同步完全的代码,例如这里就是我觉得买票的时候就只能有一个窗口在买票,其他的就不能进来.
2.同步锁,锁的是方法:
//重写Run方法
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
sellticket();//方法
}
}
private void sellticket() {
// TODO Auto-generated method stub
synchronized (TicketImpl.class) {
if(ticketNum>0){
ticketNum–;
System.out.println(Thread.currentThread().getName()+“卖出”+ticketNum+“票”);
}
}
这里自己要明白的一点这是在run方法里面写的一个方法,然后在下面锁方法
值得我们注意的是这句话synchronized (TicketImpl.class)锁的是当前的类(我也不太明白,搞懂了在给自己解释)
3.开启锁,释放锁lock
//拿到对象
Lock lo = new ReentrantLock(); //这里查看源码可以明白更多,自己记住
lo.lock();
要锁的代码
lo.unlock();
首先我要知道要想调用lock()和unlock(),必须要对象
接口 对象名 = new 类名;
类名 对象名 = new 类名;
实例化对象调用方法,你就会发现使用接口 对象名 = new 类名; 方式实例化的对象只能调用接口中有的方法,而不能调用类中特有的方法。而使用类名 对象名 = new 类名;方式创建出来的对象可以调用所有的方法

使用接口编程的好处是统一规范化。
第一种方法:同步代码块:
/**
*

  • 网上售票系统
  • @author dch

*/
public class Ticket implements Runnable {

//票的总数
static int ticket = 20;

Object obj = new Object();

//线程名字
private String name ;
//无参构造
public Ticket(){
	
}
//构造方法
public Ticket(String name){
	this.name = name ;
}

//重写Run方法
@Override
public void run() {
	// TODO Auto-generated method stub
	while (true) {
		synchronized (obj) {
			if(ticket>0){
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"--卖出"+(21-ticket)+"张票");
				ticket--;
			}
		}
	}
}

}

/**
*

  • @author dch

*/
//测试类
public class TicketTest {

public static void main(String[] args) {
	
	Ticket t = new Ticket();
	
	//创建线程对象
	Thread t1 = new Thread(t, "窗口1");
	Thread t2 = new Thread(t, "窗口2");
	Thread t3 = new Thread(t, "窗口3");
	//准备运行
	t1.start();
	t2.start();
	t3.start();
	
}

}

第二种方法:同步锁,锁的是方法:
/**
*

  • @author dch

*/
public class TicketImpl implements Runnable {

//定义一个票数
private static int ticketNum=100;

//重写Run方法
@Override
public void run() {
	// TODO Auto-generated method stub
	while(true){
		sellticket();
	}
}
//同步锁,锁的是方法
private void sellticket() {
	// TODO Auto-generated method stub
	synchronized (TicketImpl.class) {
		if(ticketNum>0){
			ticketNum--;
			System.out.println(Thread.currentThread().getName()+"卖出"+ticketNum+"票");
		}
	}
	
}

}
/**
*

  • @author dch

*/
//测试类
public class TicketTest {

public static void main(String[] args) {
	
	//创建对象
	TicketImpl ti = new TicketImpl();
	//借用Thread
	Thread t1 = new Thread(ti, "窗口1");
	Thread t2 = new Thread(ti, "窗口2");
	Thread t3 = new Thread(ti, "窗口3");
	//进入运行状态
	t1.start();
	t2.start();
	t3.start();
	
}

}

第三种 lock锁
/**
*

  • @author dch

*/
//线程用接口实现
public class TicketImpl implements Runnable {

//定义票数
private static int ticketNum = 100;
//拿到对象
Lock lo = new ReentrantLock();
//重写run方法
@Override
public void run() {
	// TODO Auto-generated method stub
	while(true){
		//开启锁
		lo.lock();
		if(ticketNum>0){
			try {
				Thread.sleep(10);
				ticketNum--;
				System.out.println(Thread.currentThread().getName()+"卖出"+ticketNum+"票");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				//释放锁
				lo.unlock();
			}
		}
	}
}

}

/**
*

  • @author dch

*/
//测试类
public class TicketTest {

public static void main(String[] args) {
	//创建线程对象
	TicketImpl ti = new TicketImpl();
	//借助Thread类创建
	Thread t1 = new Thread(ti, "窗口1");
	Thread t2 = new Thread(ti, "窗口2");
	Thread t3 = new Thread(ti, "窗口3");
	//运行
	t1.start();
	t2.start();
	t3.start();
	
}

}

猜你喜欢

转载自blog.csdn.net/qq_41035395/article/details/88955473
今日推荐