欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java之多线程安全性问题

程序员文章站 2022-05-17 19:08:30
...

小结:

同步方式:

a, 同步代码块锁对象可以是任意的对象

synchronized (锁对象) {
	可能会产生线程安全问题的代码
}

b, 同步方法  锁对象是this

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

    bb 静态同步方法 锁对象是本类名.class

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

c. Lock接口   

	//创建Lock锁对象
	Lock ck = new ReentrantLock();
         //上锁
		ck.lock();
	 添加可能会产生线程安全问题的代码		
	 //解锁
                ck.unlock();
	}

sleep: 不释放锁对象, 在休眠的时间内,不能唤醒

 wait(): 释放锁对象, 在等待的时间内,能唤醒

多线程安全问题

案例:

电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “功夫熊猫3”,本次电影的座位共100个(本场电影只能卖100张票)。

我们来模拟电影院的售票窗口,实现多个窗口同时卖 “功夫熊猫3”这场电影票(多个窗口一起卖这100张票)

public class ThreadDemo {
	public static void main(String[] args) {
		//创建票对象
		Ticket ticket = new Ticket();
		
		//创建3个窗口
		Thread t1  = new Thread(ticket, "窗口1");
		Thread t2  = new Thread(ticket, "窗口2");
		Thread t3  = new Thread(ticket, "窗口3");
		
		t1.start();
		t2.start();
		t3.start();
	}
}
Java之多线程安全性问题
public class Ticket implements Runnable {
	//共100票
	int ticket = 100;

	@Override
	public void run() {
		//模拟卖票
		while(true){
			if (ticket > 0) {
				//模拟选坐的操作
				try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);
			}
		}
	}

Java之多线程安全性问题

问题:

t0,t1,t2线程都可能出现:当各自的线程在执行完if(ticket >0)的判断后,cpu资源被抢占,线程处于阻塞状态进入等待。但是当三个线程各自拿到cpu资源时,已经不需要做if(ticket >0) 的判断,这样就可能导致t0在执行完出票操作后,ticket = 0 ,而当t1,t2线程去执行的时候,ticket会出现负数的情况。

线程同步

同步代码块:

synchronized (锁对象) {
	可能会产生线程安全问题的代码
}

同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

public class Ticket implements Runnable {
	//共100票
	int ticket = 100;
	//定义锁对象
	Object lock = new Object();
	@Override
	public void run() {
		//模拟卖票
		while(true){
			//同步代码块
			synchronized (lock){
				if (ticket > 0) {
					//模拟电影选坐的操作
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);
				}
			}
		}
	}
}
Java之多线程安全性问题
同步方法:(推荐使用
public synchronized void method(){
   	可能会产生线程安全问题的代码
}
public class Ticket implements Runnable {
	//共100票
	int ticket = 100;
	//定义锁对象
	Object lock = new Object();
	@Override
	public void run() {
		//模拟卖票
		while(true){
			//同步方法
			method();
		}
	}

//同步方法,锁对象this
	public synchronized void method(){
		if (ticket > 0) {
			//模拟选坐的操作
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);
		}
	}
}

同步方法之静态同步:

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

Q1同步方法有锁吗?

有的,同步方法中的锁对象为本类对象引用this

Q2:静态同步方法有锁吗?

有的,静态同步方法中的锁对象为本类类名.class

Q3:采用同步还有弊端吗

有的,如上例中,线程睡眠一旦产生异常,去捕获异常,同步方法不能结束,同步锁就不能被释放。因此JDK1.5后,采用Lock接口可替代synchronized

Lock接口:(强烈推荐使用

使用Lock接口,以及其中的lock()方法和unlock()方法替代同步

public class Ticket implements Runnable {
	//共100票
	int ticket = 100;
	
	//创建Lock锁对象
	Lock ck = new ReentrantLock();
	
	@Override
	public void run() {
		//模拟卖票
		while(true){
			//synchronized (lock){
			ck.lock();
				if (ticket > 0) {
					//模拟选坐的操作
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);
				}
			ck.unlock();
			//}
		}
	}
}

死锁

当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。

synchronzied(A锁){
	synchronized(B锁){
         
        }
}

Java之多线程安全性问题

  

Q1sleep()和wait()方法的区别

         sleep: 不释放锁对象, 释放CPU使用权

                    在休眠的时间内,不能唤醒

         wait(): 释放锁对象, 释放CPU使用权

                    在等待的时间内,能唤醒

Q2:为什么wait(),notify(),notifyAll()等方法都定义在Object类中

         锁对象可以是任意类型的对象