线程共享数据的安全问题和死锁问题

多线程访问共享变量的时候会出现线程安全的问题

解决线程安全的问题:线程同步(同步代码块、同步方法、同步锁)

1.同步代码块

synchronized(同步监视器){
    //需要访问的共享数据
}
同步监视器 : 俗称“锁”。可以使用任何对象充当。但是必须确定多个线程持有同一把锁(同一个对象)

2.同步方法

同步方法: ---- 隐式的锁 : this
          ----如果同步方法被静态(static)修饰后,隐式的锁是该类所属的字节码文件xxx.class(因为被static修饰,没有对象可调用此方法)
public synchronized void show(){
    //需要访问的共享数据
}

3.同步锁

public class MyRunnable implements Runnable {

	//static修饰 保证是共享资源  多个线程构造器传入同一个此对象则不必是static也可以
	public static int tick = 100;
	//创建一个锁 static修饰 保证是一个锁   多个线程构造器传入同一个此对象则不必是static也可以
	public static Lock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {
			//上锁
			lock.lock();
			try {
				if (tick > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
					}
					tick--;
					System.out.println(Thread.currentThread().getName() + "完成售票,余票为 :" + tick);
				}
			} finally {
				//必须手动解锁
				lock.unlock();
			}
		}
	}
}
public class TestLock {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Thread thread1 = new Thread(new MyRunnable(),"aa");
		thread1.start();

		Thread thread2 = new Thread(new MyRunnable(),"bb");
		thread2.start();   
	}
}
public class TestThreadDeadLock {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		MyRunnable myRunnable = new MyRunnable();

		//下面两个线程构造器都传入同一个myRunnable 则不必用上面说的static修饰共享变量
		Thread thread1 = new Thread(myRunnable, "aa");
		thread1.start();

		Thread thread2 = new Thread(myRunnable, "bb");
		thread2.start();
	}
}

打印结果

aa完成售票,余票为 :99
aa完成售票,余票为 :98
bb完成售票,余票为 :97
bb完成售票,余票为 :96
aa完成售票,余票为 :95
aa完成售票,余票为 :94
aa完成售票,余票为 :93
aa完成售票,余票为 :92
bb完成售票,余票为 :91
aa完成售票,余票为 :90
bb完成售票,余票为 :89
aa完成售票,余票为 :88
bb完成售票,余票为 :87
bb完成售票,余票为 :86
bb完成售票,余票为 :85
bb完成售票,余票为 :84
aa完成售票,余票为 :83
aa完成售票,余票为 :82
bb完成售票,余票为 :81
bb完成售票,余票为 :80
bb完成售票,余票为 :79
bb完成售票,余票为 :78
bb完成售票,余票为 :77
bb完成售票,余票为 :76
aa完成售票,余票为 :75
aa完成售票,余票为 :74
aa完成售票,余票为 :73
aa完成售票,余票为 :72
aa完成售票,余票为 :71
aa完成售票,余票为 :70
aa完成售票,余票为 :69
aa完成售票,余票为 :68
aa完成售票,余票为 :67
aa完成售票,余票为 :66
aa完成售票,余票为 :65
aa完成售票,余票为 :64
aa完成售票,余票为 :63
aa完成售票,余票为 :62
aa完成售票,余票为 :61
aa完成售票,余票为 :60
aa完成售票,余票为 :59
aa完成售票,余票为 :58
aa完成售票,余票为 :57
bb完成售票,余票为 :56
bb完成售票,余票为 :55
bb完成售票,余票为 :54
bb完成售票,余票为 :53
bb完成售票,余票为 :52
bb完成售票,余票为 :51
bb完成售票,余票为 :50
bb完成售票,余票为 :49
bb完成售票,余票为 :48
bb完成售票,余票为 :47
bb完成售票,余票为 :46
bb完成售票,余票为 :45
bb完成售票,余票为 :44
bb完成售票,余票为 :43
bb完成售票,余票为 :42
bb完成售票,余票为 :41
bb完成售票,余票为 :40
bb完成售票,余票为 :39
bb完成售票,余票为 :38
bb完成售票,余票为 :37
bb完成售票,余票为 :36
bb完成售票,余票为 :35
bb完成售票,余票为 :34
aa完成售票,余票为 :33
aa完成售票,余票为 :32
aa完成售票,余票为 :31
aa完成售票,余票为 :30
aa完成售票,余票为 :29
aa完成售票,余票为 :28
bb完成售票,余票为 :27
bb完成售票,余票为 :26
bb完成售票,余票为 :25
bb完成售票,余票为 :24
bb完成售票,余票为 :23
aa完成售票,余票为 :22
aa完成售票,余票为 :21
aa完成售票,余票为 :20
aa完成售票,余票为 :19
aa完成售票,余票为 :18
aa完成售票,余票为 :17
aa完成售票,余票为 :16
aa完成售票,余票为 :15
aa完成售票,余票为 :14
aa完成售票,余票为 :13
aa完成售票,余票为 :12
aa完成售票,余票为 :11
aa完成售票,余票为 :10
aa完成售票,余票为 :9
aa完成售票,余票为 :8
aa完成售票,余票为 :7
aa完成售票,余票为 :6
aa完成售票,余票为 :5
aa完成售票,余票为 :4
bb完成售票,余票为 :3
bb完成售票,余票为 :2
bb完成售票,余票为 :1
bb完成售票,余票为 :0

4.读写分离锁:ReentrantReadWriteLock(读读共享、写写互斥、读写互斥)

public class UseReentrantReadWriteLock {

	private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
	private ReadLock readLock = rwLock.readLock();
	private WriteLock writeLock = rwLock.writeLock();
	
	public void read(){
		try {
			readLock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
			Thread.sleep(3000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			readLock.unlock();
		}
	}
	
	public void write(){
		try {
			writeLock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
			Thread.sleep(3000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			writeLock.unlock();
		}
	}
	
	public static void main(String[] args) {
		
		final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.read();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.read();
			}
		}, "t2");
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.write();
			}
		}, "t3");
		Thread t4 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.write();
			}
		}, "t4");		
		
//		t1.start();
//		t2.start();
		
//		t1.start(); // R 
//		t3.start(); // W
		
		t3.start();
		t4.start();
	}
}

线程的死锁 : 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

匿名内部类写一个死锁

public class TestThreadDeadLock {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//锁1 内部类如果引用外部类的变,则该变量必须为final,这是规定
		final Object obj1 = new Object();
		//锁2
		final Object obj2 = new Object();

		//线程1
		new Thread(){
			public void run(){
				synchronized (obj1) {
					System.out.println("获取资源1,等待资源2......");
					try {
						//线程1获取锁1后 睡一会(此时线程1占用锁1),等待线程2获取锁2(线程2占用锁2)
						Thread.sleep(200);
					} catch (InterruptedException e) {
					}
					synchronized (obj2) {
						System.out.println("--------------------------------");
					}
				}
			}
		}.start();

//		Thread.sleep(5000);

		//线程2
		new Thread() {
			public void run() {
				synchronized (obj2) {
					System.out.println("获取资源2,等待资源1......");
					synchronized (obj1) {
						System.out.println("****************************************");
					}
				}
			}
		}.start();
	}
}
获取资源1,等待资源2......
获取资源2,等待资源1......

代码写一个死锁

public class MyRunnable implements Runnable {

	//锁1  必须是static修饰的  代表同一把锁
	public static Object obj1 = new Object();

	//锁2
	public static Object obj2 = new Object();

	public boolean flag = true;

	@Override
	public void run() {
		if(flag){
			synchronized (obj1) {
				System.out.println("获取资源1,等待资源2......");
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (obj2) {
					System.out.println("--------------------------");
				}
			}
		}else{
			synchronized (obj2) {
				System.out.println("获取资源2,等待资源1......");
				synchronized (obj1) {
					System.out.println("**************************");
				}
			}
		}
	}
}
public class TestThreadDeadLock {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		MyRunnable myRunnable1 = new MyRunnable();
		Thread thread1 = new Thread(myRunnable1);
		thread1.start();

		MyRunnable myRunnable2 = new MyRunnable();
		myRunnable2.flag = false;
		Thread thread2 = new Thread(myRunnable2);
		thread2.start();
	}
}
获取资源1,等待资源2......
获取资源2,等待资源1......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值