在多线程的处理过程之中,可以利用 Runnable 描述多个线程操作的资源,在在描述这些资源的时候,如果处理不当就会产生数据的错误操作。
一个简单的卖票程序,创建若干个线程对象来实现。
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 Test {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt, "A").start();
new Thread(mt, "B").start();
new Thread(mt, "C").start();
}
}
创建三个线程对象,这三个对象会进行五张票的出售。此时会出现问题,线程并不同步。
同步问题产生的主要原因是都在对同一数据进行处理的时候,在其他因素的影响下,会产生不希望的后果,解决这一问题的关键是”锁“:当某一个线程执行操作的时候,其他的线程在外等待。
如果想在程序之中实现锁的功能,就可以使用synchcronized
关键字,利用此关键字可以定义同步方法或同步代码块,在同步代码块的操作里只允许一个线程执行。
synchcronized(同步对象) {
同步代码操作;
}
一般进行同步对象处理的时候,可以采用当前对象进行同步。
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 Test {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt, "A").start();
new Thread(mt, "B").start();
new Thread(mt, "C").start();
}
}
加入同步处理之后,程序整体的执行性能会下降,同步会造成性能降低,异步才会达到性能的提升。
只需要在方法定义上使用synchronized
关键字即可。
class MyThread implements Runnable {
private int ticket = 10;
public synchronized void sell() {
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("票没了");
}
}
public void run() {
while (this.ticket > 0) {
this.sell();
}
}
}
public class Test {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt, "A").start();
new Thread(mt, "B").start();
new Thread(mt, "C").start();
}
}
java 类库中会发现,系统中许多类的采用的同步处理采用的都是同步方法。
死锁是在进行多线程同步的处理之中有可能产生的一种问题。指的是若干个线程彼此互相等待的状态。
class Person {
public synchronized void say(Person2 p2) {
System.out.println("Person类提示");
p2.get();
}
public synchronized void get() {
System.out.println("P1得到");
}
}
class Person2 {
public synchronized void say(Person p) {
System.out.println("Person2类提示");
p.get();
}
public synchronized void get() {
System.out.println("P2得到");
}
}
public class Test implements Runnable {
private Person p = new Person();
private Person2 p2 = new Person2();
public static void main(String[] args) {
new Test();
}
public void run() {
p.say(p2);
}
public Test() {
new Thread(this).start();
p2.say(p);
}
}
造成死锁的主要原因是因为彼此都在互相等待。死锁是开发中出现的不确定状态,如果代码处理不当则会不定期出现死锁,属于正常开发中的调试问题。
若干个线程访问统一资源时要使用同步处理,不当处理的时候就会出现死锁。