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

Java多线程:线程的同步与死锁

程序员文章站 2022-05-22 11:21:03
...

在多线程的处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,于是当多个线程访问同一资源的时候,如果处理不当就会产生数据的错误操作。

同步问题的引出

范例:创建若干个线程对象实现卖票操作

class MyThread implements Runnable{
	private int ticket = 10;
	
	public void run() {
		while(true) {
			if(this.ticket > 0) {
				try {
					Thread.sleep(100);	// 模拟网络延迟操作
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " " + this.ticket--);
			}
			else {
				System.out.println("无票");
				break;
			}
		}
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "窗口1").start();
		new Thread(mt, "窗口2").start();
		new Thread(mt, "窗口3").start();
		
		
	}
}

 

当有延迟的时候就能很轻易地看到问题所在
Java多线程:线程的同步与死锁

解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待。

使用synchronized关键字可以定义同步方法或者同步代码块;在同步代码块的操作里面的代码同一时间只允许一个线程执行。

1.利用同步代码块进行处理

synchronized(同步对象){

同步代码操作;

}

一般要进行同步对象处理的时候可以采用当前对象this进行同步。

范例:利用同步代码块解决数据同步访问问题

class MyThread implements Runnable{
	private int ticket = 10;
	
	public void run() {
		while(true) {
			synchronized(this) {	// 同步代码块
				if(this.ticket > 0) {
					try {
						Thread.sleep(100);	// 模拟网络延迟操作
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " " + this.ticket--);
				}
				else {
					System.out.println("无票");
					break;
				}
			}
		}
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "窗口1").start();
		new Thread(mt, "窗口2").start();
		new Thread(mt, "窗口3").start();
	}
}

加入同步之后,虽然不会再出现数据上出错的问题,但是程序的整体行能下降了。

2.利用同步方法解决:只需要再方法定义上使用synchronized关键字即可

class MyThread implements Runnable{
	private int ticket = 10;
	
	public synchronized boolean sale() {
		if(this.ticket > 0) {
			try {
				Thread.sleep(100);	// 模拟网络延迟操作
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " " + this.ticket--);
			return true;
		}
		else {
			System.out.println("无票");
			return false;
		}
	}
	@Override
	public void run() {
		while(true) {
			if(!this.sale()) {
				break;
			}
		}
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "窗口1").start();
		new Thread(mt, "窗口2").start();
		new Thread(mt, "窗口3").start();
	}
}

使用同步代码块和同步方法并没有多大差别,但是再Java类库许多类上的同步处理都是用的是同步方法。

死锁

死锁是再进行多线程同步处理中有可能出现的问题。所谓的死锁指的是若干个线程彼此互相等待的状态。

范例:

package threads;

class test1{
	public synchronized void func(test2 t2) {
		System.out.println("我是test1,需要一个test2的对象");
		t2.get();
	}
	public synchronized void get() {
		System.out.println("我是test1,得到了一个test2的对象");
	}
}

class test2{
	public synchronized void func(test1 t1) {
		System.out.println("我是test2, 需要一个test1的对象");
		t1.get();
	}
	public synchronized void get() {
		System.out.println("我是test2,得到了一个test1的对象");
	}
}

public class DeadLock implements Runnable{
	private test1 t1 = new test1();
	private test2 t2 = new test2();
	public DeadLock() {
		new Thread(this).start();	// 新启动一个线程
		t2.func(t1);
	}
	@Override
	public void run() {
		t1.func(t2);
	}

	public static void main(String[] args) {
		new DeadLock();
		
	}

}

造成死锁的原因是互相等待。

若干个线程访问同一资源时一定要进行同步处理,而过多的同步处理会造成死锁。

死锁是同步引起的。