摘要:上一篇文章,写了实现java多线程的方式,以售票为示例来说明,可是我们看到和我们实际有很大的问题,这一骗文章主要用同步块和同步方法,解决售票问题,以实现Runnable接口为例。
为什么要用同步块或同步方法?
同步代码块和同步方法可以将操作共享数据的多条代码块封装起来,当线程在执行这些代码的时候,其他线程是不会参与进来运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
同步代码块的格式:
synchronized(对象)
{
需要被同步的代码 ;
}
同步函数的格式:
Synchronized 返回值类型 方法名([参数1,……]){}
同步代码块实现同步原理:
同步代码块中传入的对象是一个锁对象。当线程执行同步代码块时,首先线程会检查对象的标志位,默认情况下标志位为1,此时线程会执行同步代码块,同时锁对象的标志位置为0.当一个新线程执行到这段同步代码块时,有哟锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代码。循环往复,直到共享资源被处理完为止。
class Ticket implements Runnable{
private int num = 10;
Object lock = new Object();
public void run(){
while(true){
synchronized(lock){
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
if(num>0){
System.out.println(Thread.currentThread().getName()+"....."+num--);
}else{
break;//小于等于0跳出循环
}
}
}
}
}
class SynDemo1{
public static void main(String[] args){
Ticket t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
运行结果:
注意:同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是唯一的,”任意”说的是共享锁对象的类型。所以锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象,这每个线程都会有一个不同的锁,每个锁都有自己的标志位。线程直接便不能产生同步效果。
同步方法实现同步原理:
同步方法实现原理和同步代码块实现原理相同,所不同的是,锁对象。
同步方法的锁是当前调用该方法的对象,也就是this指向的对象。这样做的好处是,同步方法被所有线程所共享,方法所在的对象相对于所有线程来时是唯一的,从而保证了锁的唯一性,当一个线程执行该方法时,其他线程就不能进去改方法中,直到这个线程执行完该方法为止,从而达到了线程同步的效果。
class Ticket implements Runnable{
private int num = 10;
public void run(){
while(true){
saleTicket();
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
if(num<=0)
break;
}
}
private synchronized void saleTicket(){
if(num>0)
System.out.println(Thread.currentThread().getName()+"....."+num--);
}
}
class SynDemo2{
public static void main(String[] args){
Ticket t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
运行结果:
有时候需要同步的方法是静态方法,静态方法不需要创建对象就可以直接用“类名.方法名()”的方式调用。这时java中静态方法的锁是改方法所在类的class对象,获取方式用getClass()或“类名.class”。
class Ticket implements Runnable{
private static int num = 10;
boolean flag = true;
public void run(){
if(flag)
while(true)
{
synchronized(Ticket.class){//(this.getClass())
if(num>0){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+".....obj...."+num--);
}
}
}
else
while(true)
this.show();
}
public static synchronized void show(){
if(num>0){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+".....function...."+num--);
}
}
}
class SynDemo3 {
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(t).start();
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
t.flag = false;
new Thread(t).start();
}
}
运行结果: