0302 线程状态、线程安全

线程状态

1、新建状态

2、受阻塞状态

3、运行状态

4、死亡状态

5、休眠状态

6、等待状态

线程安全

当多条线程共用一份资源的时候就睡产生线程安全,比如电影院我们有100张票,同时有三个渠道去卖这100张票,看一下案例思维图

 我们来模拟一下这个场景

首先创建一个线程类 实现Runnable接口,并且重写run方法

public class Ticket implements Runnable{
	private int num=100;
	//卖票
	public void run() {
		while(true){
			if(num>0){
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"卖出了第"+num--+"张票");
			}
		}
	}
}

  

创建一个测试类,创建三条线程去卖票

	public static void main(String[] args) {
		//创建线程任务
		Ticket t=new Ticket();
		//创建三条线程
		Thread t1=new Thread(t);
		Thread t2=new Thread(t);
		Thread t3=new Thread(t);
		//开启线程
		t1.start();
		t2.start();
		t3.start();
	}

  根据运行结果会发现,会有第0张和第-1张 还有可能会出现多条线程卖同一张票的情况

 这就出现了线程安全问题,解决这个线程安全的方法

1、同步代码块

2、同步方法

3、lock接口

用到的是Synchronized关键字

1、同步代码块格式

synchronized (锁对象) {

    可能会产生线程安全问题的代码

}

同步代码块的锁对象可以是任意对象,但要保证该对象是唯一的

代码展示

public class Ticket02 implements Runnable{

	private int num=100;
	//定义一个锁对象
	private Object obj=new Object();
	//卖票
	public void run() {
		while(true){
			synchronized (obj) {
				if(num>0){
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"卖出了第"+num--+"张票");
				}
			}
		}
	}
}

  

2、同步方法

格式:

public synchronized void method(){

     可能会产生线程安全问题的代码

}

代码展示

public class Ticket03 implements Runnable{

	private int num=100;
	//卖票
	public void run() {
		while(true){
			sale();
		}
	}
	//同步方法
	public synchronized void sale(){
		if(num>0){
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"卖出了第"+num--+"张票");
		}
	}
}

  

3、lock接口

在loc接口中有两个方法

(1)lock()获取锁

(2)unlock()释放锁

因为lock是个接口 那我们需要创建他的子类对象ReentrantLock去使用

代码展示

public class Ticket04 implements Runnable{

	private int num=100;
	//定义锁对象
	private Lock lock=new ReentrantLock();
	//卖票
	public void run() {
		while(true){
			//获取锁
			lock.lock();
			if(num>0){
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"卖出了第"+num--+"张票");
			}
			//释放锁
			lock.unlock();
		}
	}
}

  

那我们回想一下StringBuffer和StringBuilder这两个类完全相同,唯一的区别是StringBuilder比StringBuffer速度要快,是因为StringBuffer底层方法都用了Synchronized关键字,也就是说StringBuffer类能够保证线程安全,但StringBuilder类是不保证线程安全的,所以StringBuilder类适合在单线程中使用。

原文地址:https://www.cnblogs.com/-gongxue/p/14467612.html