在多线程的处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,当然多个线程访问同一资源时如果处理不当,就会产生数据的错误操作。
同步问题的引出
现在编写一个简单的卖票程序,将若干个线程对象实现卖票的处理操作。
范例:实现卖票操作
class MyThread implements Runnable {
private int ticket = 10;//总票数为10张
@Override
public void run() {
while (true) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
} else {
System.out.println("***** 票卖光了 *****");
break;
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
MyThread mt=new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
}
}
此时的程序将创建3个线程对象,并且这三个线程将进行10张票的出售。此时的程序在进行卖票处理的时候,并没有任何的问题(假象),下面可以模拟一下卖票中的延迟操作。
class MyThread implements Runnable {
private int ticket = 10;//总票数为10张
@Override
public void run() {
while (true) {
if (this.ticket > 0) {
try {
Thread.sleep(100);//模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
} else {
System.out.println("***** 票卖光了 *****");
break;
}
}
}
}
这个时候追加了延迟问题就暴露出来了,而实际上这个问题一直都在。
卖票处理
线程同步
经过分析之后已经可以确定同步问题产生的主要原因了,那么下面就需要进行同步问题的解决,但是解决问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待;
问题的解决
如果想程序中实现锁功能,就可以使用synchronized关键字来是吸纳,利用synchronized可以定义同步方法和同步代码块,在同步代码块的操作中的代码只允许一个线程执行。
1、利用同步代码块进行处理:
synchronized (同步对象){
同步代码操作;
}
一般要进行同步对象处理时,可以采用当前对象this进行同步。
范例:利用同步代码块解决数据同步访问问题
class MyThread implements Runnable {
private int ticket = 1000;//总票数为10张
@Override
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() + "卖票,ticket = " + this.ticket--);
} else {
System.out.println("***** 票卖光了 *****");
break;
}
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
new Thread(mt, "票贩子A").start();
new Thread(mt, "票贩子B").start();
new Thread(mt, "票贩子C").start();
}
}
加入同步处理之后,程序的整体性能下降了。同步实际上会造成性能的降低。
2、利用同步方法解决:只需要在方法定义上使用synchronized关键字即可。
class MyThread implements Runnable {
private int ticket = 10;//总票数为10张
public synchronized boolean sale() {
if (this.ticket > 0) {
try {
Thread.sleep(100);//模拟网络延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + 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();
new Thread(mt, "票贩子A").start();
new Thread(mt, "票贩子B").start();
new Thread(mt, "票贩子C").start();
}
}
在日后学习Java类库时,系统中许多的类上使用的同步处理采用的都是同步方法。
死锁
死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此互相等待的状态。
public class DeadLock implements Runnable {
private Producer producer = new Producer();
private Customer customer = new Customer();
public DeadLock() {
new Thread(this).start();
customer.say(producer);
}
public static void main(String[] args) {
new DeadLock();
}
@Override
public void run() {
producer.say(customer);
}
}
class Producer {
public synchronized void say(Customer customer) {
System.out.println("店员:先买单后吃饭");
customer.get();
}
public synchronized void get() {
System.out.println("收到钱,可以给你做饭了");
}
}
class Customer {
public synchronized void say(Producer producer) {
System.out.println("顾客:先吃饭后买单");
producer.get();
}
public synchronized void get() {
System.out.println("吃饱饭了,可以买单了");
}
}
现在死锁造成的主要原因是因为彼此都在互相等待着,等待着对方先让出资源。死锁实际上是一种开发中出现的不确定的状态,有时代码处理不当,则会不定期出现死锁,这属于正常开发中的调试问题。
若干个线程访问同一资源时一定要进行同步处理,但过多的同步会造成死锁。
网友评论