线程的同步:在编程过程中,为了防止多线程访问共享资源时发生冲突,Java提供了线程同步机制。所谓同步,就是指一个线程等待另一个线程操作完再继续的情况。
线程安全:一个类很好地同步以保护它的数据,这个类就称为线程安全的。
线程不安全:多个线程先后更改数据造成某些线程得到的是无效数据。
概念比较抽象,通过下面的程序来解释:
this.ticket–表达式的结果为ticket的当前值,因此每次输出的ticket是当前的票数。但是由输出结果可以看到最后输出的:“售票员B卖票.ticket = 0”。这就和之前的if(this.ticket > 0) 产生了冲突,为什么ticket=0,仍然能进入if循环呢?
这就是由于不同步所造成的,程序在运行过程中需要完成两步操作:
1.判断是否还有票
2.卖票
但是步骤1和2之间出现了延迟。假设现在只剩下最后一张票,所有线程几乎同时进入run()方法执行,此时if判断条件都满足,再执行自减操作就会有错误。这就是线程不同步。
package com.thred;class MyThread implements Runnable {//线程主体类private int ticket = 6;@Overridepublic void run() {//理解为线程的主方法for(int x = 0; x < 50; x++) {if(this.ticket > 0) {//卖票的条件try {Thread.sleep(1000);}catch(InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖票.ticket = " + this.ticket--);//this.ticket--表达式的结果为ticket的当前值}}}
}
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();}
}
/*
售票员A卖票.ticket = 6
售票员C卖票.ticket = 6
售票员B卖票.ticket = 5
售票员A卖票.ticket = 4
售票员C卖票.ticket = 3
售票员B卖票.ticket = 2
售票员A卖票.ticket = 1
售票员C卖票.ticket = 1
售票员B卖票.ticket = 0
*/
怎么解决线程不同步问题?同步代码块,同步方法块。解决了不同步问题,但是程序执行速度变慢,安全性高,性能降低了。
目前只是入门,只简单的写一下怎么用,原理的东西等后面深入学习再补充。
同步代码块:使用Synchronized关键字定义的代码块,同步时需要设置一个对象锁,一般是给当前对象this上锁。
package com.thred;class MyThread implements Runnable {//线程主体类private int ticket = 6;@Overridepublic void run() {//理解为线程的主方法for(int x = 0; x < 50; x++) {synchronized(this) {//同步代码块if(this.ticket > 0) {//卖票的条件try {Thread.sleep(1000);}catch(InterruptedException e) {e.printStackTrace();}
System.out.println(Thread.currentThread().getName() + "卖票.ticket = " + this.ticket--);}}}}
}
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();}
}
/*
售票员A卖票.ticket = 6
售票员A卖票.ticket = 5
售票员A卖票.ticket = 4
售票员A卖票.ticket = 3
售票员A卖票.ticket = 2
售票员A卖票.ticket = 1
*/
同步方法:在一个方法上使用synchronized定义,此方法称为同步方法。
package com.thred;class MyThread implements Runnable {//线程主体类private int ticket = 6;@Overridepublic void run() {//理解为线程的主方法for(int x = 0; x < 50; x++) {this.sale();}}public synchronized void sale() {//同步方法if(this.ticket > 0) {//卖票的条件try {Thread.sleep(1000);}catch(InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖票.ticket = " + this.ticket--);}}
}
public class Test {public static void main(String[] args) {MyThread mt = new MyThread();new Thread(mt, "售票员B").start();new Thread(mt, "售票员A").start();new Thread(mt, "售票员C").start();}
}
/*
售票员B卖票.ticket = 6
售票员B卖票.ticket = 5
售票员B卖票.ticket = 4
售票员B卖票.ticket = 3
售票员B卖票.ticket = 2
售票员B卖票.ticket = 1
*/