同步问题的引出
在多线程的处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,于是当多个线程访问同一资源的时候如果处理不当就会产生数据的错误操作。
创建若干个对象实现卖票的处理操作。
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="+ticket--);
}
else{
System.out.println("票已经卖光了");
break;
}
}
}
}
public class ThreadDemo {
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();
}
}
/**追加延迟后更容易观察
其中一次运行结果为
线程B卖票,ticket=9
线程A卖票,ticket=8
线程C卖票,ticket=10
线程B卖票,ticket=5
线程A卖票,ticket=7
线程C卖票,ticket=6
线程B卖票,ticket=4
线程C卖票,ticket=3
线程A卖票,ticket=2
线程B卖票,ticket=1
票已经卖光了
线程C卖票,ticket=-1
票已经卖光了
线程A卖票,ticket=0
票已经卖光了
Process finished with exit code 0
对出现-1的情况进行分析:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nKqRkII7-1679990855548)(…\img\同步引出.jpg)]
线程同步处理
线程同步
经过分析之后可以确认同步问题所产生的主要原因了,那么,下面就需要进行同步问题的解决,解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待。
问题的解决
想要解决这样的问题,必须使用同步,同步就是指多个操作在同一时间段内只能有一个线程进行,其他线程要等此线程完成之后才可以继续执行。如果想要在程序之中实现这把锁的功能,就可以实现synchronized关键字来实现,利用此关键字可以定义同步方法或同步代码块,在同步代码块的操作里面的代码只允许一个线程执行。
-
利用同步代码块进行处理
synchronized(同步对象){ 同步代码操作; }
一般要进行同步对象处理的时候可以采用当前对象this进行同步。
范例 利用同步代码块解决同步访问问题:
class MyThread implements Runnable{ private int ticket=10;//总票数为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=" + ticket--); } else { System.out.println("票已经卖光了"); break; } } } } } public class ThreadDemo { 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;//总票数为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=" + 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) { MyThread mt=new MyThread(); new Thread(mt,"线程A").start(); new Thread(mt,"线程B").start(); new Thread(mt,"线程C").start(); } }
在日后使用java类库的时候会发现,系统上许多的类上使用的同步处理采用的都是同步方法。
死锁
死锁是在多线程同步的处理之中可能出现的一种问题,所谓的死锁指的是若干进程彼此相互等待的状态。
死锁实际上是一种开发中出现的不确定的状态,有时候如果代码处理不当则会不定期出现死锁,这属于正常开发中的调试问题。若干个线程访问同一资源的时候一定要进行同步处理,而过多的同步则会造成死锁。
采用的都是同步方法。
死锁
死锁是在多线程同步的处理之中可能出现的一种问题,所谓的死锁指的是若干进程彼此相互等待的状态。
死锁实际上是一种开发中出现的不确定的状态,有时候如果代码处理不当则会不定期出现死锁,这属于正常开发中的调试问题。若干个线程访问同一资源的时候一定要进行同步处理,而过多的同步则会造成死锁。