先举一个反例(关于卖票的例子)
注:为了简洁,文章不打@注释,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();
}
}
结果:
一、同步代码块: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();
}
}
二,静态代码块:
把一个方法变成静态之后就是类级别的方法,这时再加锁——建多个对象时他们就同时只能用一个。
注意;这是类级别的锁,所以建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();
}
}
我们需要思考的是,如果之加锁但是没有加静态会怎么样呢?那么建了4个对象,每个对象分别加一个锁,都是独立的,就没有用了。
三,下面的这个是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();
}