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();
}
}
当有延迟的时候就能很轻易地看到问题所在
解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待。
使用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();
}
}
造成死锁的原因是互相等待。
若干个线程访问同一资源时一定要进行同步处理,而过多的同步处理会造成死锁。
死锁是同步引起的。