- 在多线程处理之中可以利用Runnable描述多个线程操作的资源,而Thread类描述每一个线程对象,于是当多个线程访问统一资源的时候如果处理不当就会产生数据的错误操作;
同步问题的引出
- 下面编写一个卖票程序,将创建若干个线程对象实现买票的处理操作;
//
package com.company;
class MyThread implements Runnable {
private int ticket = 10;
@Override
public void run() {
while (true) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出去一张票,当前还剩" + this.ticket--);
} else {
System.out.println("******* 票卖完了 *******");
break;
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
Thread threadA = new Thread(mt, "票贩子A");
Thread threadB = new Thread(mt, "票贩子B");
Thread threadC = new Thread(mt, "票贩子C");
threadA.start();
threadB.start();
threadC.start();
}
}
- 此时的程序将创建三个线程对象,并且这三个线程对象将进行10张票的出售,此时的程序在进行买票处理的时候并没有任何的问题(假象),下面模拟一下卖票中的延迟操作:
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;
}
- 追加了延迟问题就暴露出来了,但是这个问题是一直都在的;
此图来源于李兴华老师
线程同步处理
- 经过分析之后已经可以确认同步问题所产生的主要原因,那么就需要进行同步问题的解决,但是解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待;
此图来源于李兴华老师
- 如果要想在程序之中实现这把锁的功能,可以使用synchronized关键字来实现,利用此关键字可以定义同步方法或同步代码块,在同步代码块的操作里面的代码只允许一个线程执行:
synchronized(同步对象) {
同步代码操作;
}
- 一般进行同步对象处理的时候可以采用当前对象this进行同步;
//利用同步代码块解决数据同步访问问题
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;
}
}
- 加入同步处理之后,程序的整体性能下降了,同步实际上会造成性能的降低;
//利用同步方法解决:只需要在方法定义上使用synchronized关键字即可
package com.company;
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 (this.sale()) {
;
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
Thread threadA = new Thread(mt, "票贩子A");
Thread threadB = new Thread(mt, "票贩子B");
Thread threadC = new Thread(mt, "票贩子C");
threadA.start();
threadB.start();
threadC.start();
}
}
线程的死锁
- 死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此等待的状态;
//死锁的展示
package com.company;
public class DeadLock implements Runnable {
private LockA a = new LockA();
private LockB b = new LockB();
@Override
public void run() {
a.say(b);
}
public DeadLock() {
new Thread(this).start();
b.say(a);
}
public static void main(String[] args) {
new DeadLock();
}
}
class LockA {
public synchronized void say(LockB b) {
System.out.println("线程A说:线程B你让我先运行");
b.get();
}
public synchronized void get() {
System.out.println("线程B说了让我先运行");
}
}
class LockB {
public synchronized void say(LockA a) {
System.out.println("线程B说:线程A你让我先运行");
a.get();
}
public synchronized void get() {
System.out.println("线程A说了让我先运行");
}
}
- 死锁造成的主要原因是因为彼此都在互相等待,等待对方先让出资源,死锁实际上是开发中出现的不确定的状态;
- 若干个线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁;
网友评论