Java 多线程 02 线程安全、同步、死锁

1 线程安全

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全问题都是由全局变量静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

线程不安全代码示例:

public class MyRunnable implements Runnable {

	// 总共50张票
	int ticket = 50;

	@Override
	public void run() {
		
		// 模拟卖票
		while (true) {
			if (ticket>0) {
				try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+" is sailing.... "+ticket--);
			}
		}
	}
}


public static void main(String[] args) {

	MyRunnable myRunnable=new MyRunnable();
	
	Thread t1=new Thread(myRunnable,"window 1");
	Thread t2=new Thread(myRunnable,"window 2");
	Thread t3=new Thread(myRunnable,"window 3");
	
	t1.start();
	t2.start();
	t3.start();
}

// 运行结果:
window 3 is sailing.... 5
window 1 is sailing.... 4
window 2 is sailing.... 3
window 3 is sailing.... 2
window 2 is sailing.... 1
window 1 is sailing.... 0	// 出现问题
window 3 is sailing.... -1	// 出现问题

2 线程同步

线程同步有两种方式:

  • 同步代码块
  • 同步方法
2.1 同步代码块

格式:

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

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

示例:

public class MyRunnable implements Runnable {

	// 总共500张票
	int ticket = 500;

	// 定义锁对象
	Object lock = new Object();

	@Override
	public void run() {

		// 模拟卖票
		while (true) {
			// 同步代码块
			synchronized (lock) {
				if (ticket > 0) {
					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " is sailing.... " + ticket--);
				}
			}
		}
	}
}
2.2 同步方法

格式:

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

示例:

public class MyRunnable implements Runnable {

	// 总共50张票
	int ticket = 500;

	// 同步方法,锁对象this
	public synchronized void method() {
		if (ticket > 0) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " is sailing.... " + ticket--);
		}
	}

	@Override
	public void run() {

		// 模拟卖票
		while (true) {
			// 同步方法
			method();
		}
	}
}

3 死锁

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

4 Lock接口

示例:

public class MyRunnable implements Runnable {

	// 总共500张票
	int ticket = 500;

	// 1 创建lock锁对象
	Lock ck=new ReentrantLock();

	@Override
	public void run() {

		// 模拟卖票
		while (true) {
			// 2 获取锁
			ck.lock();
			
			if (ticket > 0) {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " is sailing.... " + ticket--);
			}
			
			// 3 释放锁
			ck.unlock();
			
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值