线程安全问题出现的原因和解决方法

线程安全问题出现的根本原因:

    1. 必须要存在两个或者两个以上的线程共享着一个资源。

    2. 操作共享资源的代码必须有两句或者两句以上。

线程安全问题的解决方案(2个):

解决思路:

就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的。

必需要当前线程把这些带那都执行完毕后,其他线程才能参与运算。

同步的好处:解决了线程的安全问题。

同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁。

同步的前提:同步中必须有多个线程并使用同一个锁。

    1. 同步代码块

        synchronized(锁){

            需要被同步的代码

        }

class SaleTicket extends Thread{
	 static int num = 50;//票数  非静态的成员变量,非静态的成员变量数据是在每个对象中都会维护一份数据的。
	 public SaleTicket(String name) {
		super(name);
	}
	
	@Override
	public void run() {
		while(true){
			//同步代码块
			synchronized ("锁") {				
				if(num>0){
					System.out.println(Thread.currentThread().getName()+"售出了第"+num+"号票");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					num--;
				}else{
					System.out.println("售罄了..");
					break;
				}
			}			
		}
	}			
} 
public class Demo4 {	
	public static void main(String[] args) {
		//创建三个线程对象,模拟三个窗口
		SaleTicket thread1 = new SaleTicket("窗口1");
		SaleTicket thread2 = new SaleTicket("窗口2");
		SaleTicket thread3 = new SaleTicket("窗口3");
		//开启线程售票
		thread1.start();
		thread2.start();
		thread3.start();		
	}	
}

同步代码块需要注意的事项注意:

1. 同步代码块的锁可以是任意的对象。 同步函数的锁是固定的,非静态函数的锁对象是this对象。 静态函数的锁对象是class对象。

2. 锁对象必须是多线程共享的对象,否则锁不住。

3. 在同步代码块或者是同步函数中调用sleep方法是不会释放锁对象的,如果是调用了wait方法是会释放锁对象的。

    2. 同步函数。 

        修饰符 synchronized 返回值类型   函数名(形参列表..){

        }

class BankThread extends Thread{
	static int count = 5000;
	public BankThread(String name){
		super(name);
	}
	
	@Override  //
	public synchronized  void run() {
		while(true){
			synchronized ("锁") {				
				if(count>0){
					System.out.println(Thread.currentThread().getName()+"取走了1000块,还剩余"+(count-1000)+"元");
					count= count - 1000;
				}else{
					System.out.println("取光了...");
					break;
				}
			}
		}
	}
 
public class Demo1 {
 
	public static void main(String[] args) {
		//创建两个线程对象
		BankThread thread1 = new BankThread("老公");
		BankThread thread2 = new BankThread("老婆");
		//调用start方法开启线程取钱
		thread1.start();
		thread2.start();	
	}
	
}

同步函数注意事项:

1.如果函数是一个非静态的同步函数,那么锁对象是this对象;

2.如果函数是静态的同步函数,那么锁对象是当前函数所属的类的字节码文件(class对象);

3.同步函数的锁对象是固定的,不能由自己指定。

 同步函数和同步代码块的区别:

同步函数的锁是固定的this;

同步代码块的锁是任意的对象。

建议使用同步代码块。

静态的同步函数使用的锁是该函数所属字节码文件对象

可以用getClass()方法来获取,也可以用当前 类名.class表示