JAVA基础多线程(2)—线程同步

先举一个反例(关于卖票的例子)

注:为了简洁,文章不打@注释,set,get,构造函数,异常等

 

这个程序就是模拟买票的窗口,new一个SellTicket,然后5个窗口一起卖,从结果可以看出,实际是卖的乱了。

public class SellTicket implements Runnable{

    private int ticketCount=10;

    private void sellTicket(){
        if (ticketCount>0){
            ticketCount--;
            System.out.println(Thread.currentThread().getName()+"卖的票,库存还剩:"+ticketCount+"张");
        }
    }

    public void run() {
        while(ticketCount>0){
        sellTicket();
        }
        Thread.sleep(10);    //不加sleep看不出效果,但是与程序本身无关
        }
    }
public class Main {

    public static void main(String[] args) throws InterruptedException {

        SellTicket sellTicket= new SellTicket();

        Thread thread1=new Thread(sellTicket);

        Thread thread2=new Thread(sellTicket);

        Thread thread3=new Thread(sellTicket);

        Thread thread4=new Thread(sellTicket);

        Thread thread5=new Thread(sellTicket);

        thread1.start();

        thread2.start();

        thread3.start();

        thread4.start();

        thread5.start();
    }
}

结果:

JAVA基础多线程(2)—线程同步

一、同步代码块:synchronized  

    当一个对象被同时操作的时候就用到了同步代码块,比如买票的程序,synchronized()的参数是对象,可以new一个object也可以直接放this,代表锁住当前的对象,当synchronized代码块被执行的时候,对象就被锁住了,执行完之后就打开锁

下边这个例子是同步代码块,把锁加在了方法上,其实呢还可以加在类上,这得看实际的需求,向下边的这例子代码没几行,无所谓,但是如果是一个很大的类,你把锁加在了类上,其他不需要同步的方法也要等,就严重的影响了运行速度。

public class SellTicket implements Runnable{
    private int ticketCount=10;
    private Object object=new Object();

    private void sellTicket(){
               synchronized (object){
        if (ticketCount>0){
            ticketCount--;
            System.out.println(Thread.currentThread().getName()+"卖的票,库存还剩:"+ticketCount+"张");
        }
       }
    }

    public void run() {
            while(ticketCount>0){
            sellTicket();
            Thread.sleep(10);
     }
 }
public class Main {
    public static void main(String[] args) throws InterruptedException {

        SellTicket sellTicket= new SellTicket();

        Thread thread1=new Thread(sellTicket);
        Thread thread2=new Thread(sellTicket);
        Thread thread3=new Thread(sellTicket);
        Thread thread4=new Thread(sellTicket);
        Thread thread5=new Thread(sellTicket);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
    }
}

JAVA基础多线程(2)—线程同步

 

二,静态代码块:

把一个方法变成静态之后就是类级别的方法,这时再加锁——建多个对象时他们就同时只能用一个。

 

 注意;这是类级别的锁,所以建4个对象,分别放在4个线程是没有关系的,因为4个对象公用的一个类锁。

public class SellTicket implements Runnable{

     static int ticketCount=10;

     protected synchronized static void sellTicket(){
        if (ticketCount>0){
            ticketCount--;
            System.out.println(Thread.currentThread().getName()+"卖的票,库存还剩:"+ticketCount+"张");
        }
    }

    public void run() {

            while(ticketCount>0){
            SellTicket.sellTicket();
        }
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {

        SellTicket sellTicket1= new SellTicket();
        SellTicket sellTicket2= new SellTicket();
        SellTicket sellTicket3= new SellTicket();

        Thread thread1=new Thread(sellTicket1);
        Thread thread2=new Thread(sellTicket2);
        Thread thread3=new Thread(sellTicket3);

        thread1.start();
        thread2.start();
        thread3.start();
}
}

JAVA基础多线程(2)—线程同步

 

我们需要思考的是,如果之加锁但是没有加静态会怎么样呢?那么建了4个对象,每个对象分别加一个锁,都是独立的,就没有用了。

JAVA基础多线程(2)—线程同步

JAVA基础多线程(2)—线程同步

 

三,下面的这个是wait和notifier  

这里只是做个例子,什么时候工作用到了就理解了

wait()就是等待,等着别人唤醒

notifyAll()是唤醒所有的线程,notify()随机唤醒其中一个线程。

Message只是一个普通类,用来模拟正常类的运行 

public class Message {
private String msg;

public String getMsg() {return msg;}

public void setMsg(String msg) {this.msg = msg;}

public Message(String msg) {this.msg = msg;}
}

Wait类演示的是进程里wait() 使当前线程阻塞,

public class Wait implements Runnable{

    private Message msg;

@Override
public void run() {
    String name =Thread.currentThread().getName();

   synchronized (msg){ //这个wait和notifier必须在synchronized代码块里写,否则会抛异常
    try {
        System.out.println(name+"等待时间"+System.currentTimeMillis());
        msg.wait();
        System.out.println(msg.getMsg()+System.currentTimeMillis());
    } catch (InterruptedException e) {
         e.printStackTrace();
        }
      }
   }
}

notifyAll()是唤醒所有的线程,notify()随机唤醒其中一个线程。

public class Notifier implements Runnable {

    private Message msg;

    @Override
    public void run() {
        String name=Thread.currentThread().getName();
        synchronized (msg){
        msg.setMsg("唤醒线程工作:");
        msg.notifyAll();
        // msg.notify();
        }
    }
}

 

public class Main {

public static void main(String[] args) {

     Message msg=new Message("m1");      
     Wait wait=new Wait(msg);
     Wait wait1=new Wait(msg);
     Notifier notifier =new Notifier(msg);

     new Thread(wait,"wait").start();
     new Thread(wait1,"wait1").start();
     new Thread(notifier,"notifier").start();
}

JAVA基础多线程(2)—线程同步