当多个线程共享一份数据,执行相同任务的时候,会发生线程安全问题
当四个线程执行start()方法之后,这时候,CPU是随机的,四个线程同时抢CPU,若是thread1抢到,当他用完时间片,四个线程再一块儿抢时间片,这时候也不必定谁能抢到,当时间片用完的时候,须要当即释放,那么可能会停在执行任务的run方法里面,假设停在了 ticket.num = ticket.num-1;这,等thread2 ,thread3,thread4也停在这里,这样等线程再抢到时间片的时候,就会发生数据错误的状况,这样就繁盛了线程不安全的状况,这样就能够用锁解决
java
public class Demo1 { public static void main(String[] args) { Sell sell = new Sell(); //四个线程,把线程和任务绑定在一块儿 Thread thread1 = new Thread(sell); Thread thread2 = new Thread(sell); Thread thread3 = new Thread(sell); Thread thread4 = new Thread(sell); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } } //四个线程共享一份数据 class Ticket{ int num = 2000; } //这个是卖票任务 class Sell implements Runnable{ Ticket ticket = new Ticket(); @Override public void run() { while (true){ ticket.num = ticket.num-1;//假设四个线程用完时间片都停在了这,当再次抢到时间片的时候,数据就会发生错误 System.out.println(Thread.currentThread().getName()+"卖票了"+"还剩"+ticket.num+"张票"); } } }
咱们须要给加一把锁,而且必须他们四个共享的锁,这时候就能避免当thread1 线程用完时间片,可是他仍是在锁里面,虽然他释放了时间片,可是必须等他再次抢到CPU的时候,全都执行完这个代码,这时候其余三个线程才有资格进来,能解决线程安全的问题安全
class Sell implements Runnable{ Ticket ticket = new Ticket(); @Override public void run() { while (true){ synchronized (ticket){ ticket.num = ticket.num-1; System.out.println(Thread.currentThread().getName()+"卖票了"+"还剩"+ticket.num+"张票"); } } } }
上锁能够上字节码文件对象,两个共有的,还有this
当咱们有一份数据,两个线程和两个任务的时候,是打印和输出任务
这时候我应该打印出来 name:zhangage:19或者 name:liage:20,可是出来的时候有时候年龄和姓名不匹配也是发生了线程安全问题,当
thread1 抢到了时间片,多是卡在了age 和name 那,等到thread2抢到时间片的时候,打印就是错误的结果,这时候咱们应该给thread1 加锁,可是打印thread2 也有可能出现线程安全问题,因此打印年龄和名字仍是 不匹配,这样的状况咱们就应该给Syst 和Print 同时上一把锁,这样person 就是最合适的
ide
public class Demo2 { public static void main(String[] args) { Person person = new Person("zhang",20); Print print = new Print(person); Syst syst = new Syst(person); Thread thread1 = new Thread(print); Thread thread2 = new Thread(syst); thread1.start(); thread2.start(); } } class Person{ String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } } class Print implements Runnable{ int i = 1; Person person; public Print(Person person) { this.person = person; } @Override public void run() { while (true){ synchronized (person){ if(i%2==0){ person.name = "zhang"; person.age = 19; }else{ person.name = "li"; person.age = 20; } i = i+1; } } } } class Syst implements Runnable{ Person person ; public Syst(Person person) { this.person = person; } @Override public void run() { while (true){ synchronized (person){ System.out.println(Thread.currentThread().getName()+" " +"name:"+person.name+"age:"+person.age); } } } }
可是对于打印来讲,应该是一次输入一次输出才对,因此就要写唤醒等待机制,当thread1 能够抢CPU的时候,thread2等待,暂时 失去抢CPU的能力,当thread1执行完后,他就进入了wait,thread2抢到CPU执行任务,这样就会交替进行this
class Person1{ String name; int age; boolean flag = false;//用于执行唤醒等待的切换 public Person1(String name, int age) { this.name = name; this.age = age; } } class Print1 implements Runnable{ int i = 1; Person1 person; public Print1(Person1 person) { this.person = person; } @Override public void run() { while (true){ synchronized (person){ if(person.flag==true){ try { person.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(i%2==0){ person.name = "zhang"; person.age = 19; }else{ person.name = "li"; person.age = 20; } i = i+1; person.flag = !person.flag; person.notify(); } } } } class Syst1 implements Runnable{ Person1 person ; public Syst1(Person1 person) { this.person = person; } @Override public void run() { while (true){ synchronized (person){ if(person.flag==false){ try { person.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+" " +"name:"+person.name+"age:"+person.age); person.flag = !person.flag; person.notify(); } } } }
咱们除了能够用唤醒等待机制意外,还能够用Lock和Condition 搭配使用,在单消费者和单生产者中,用哪一个都同样,可是到了多生产者和多消费者的状况下,若是使用synchronized 会用到 notifyAll();这样会把对方所有的线程唤醒,spa
public class Demo5 { public static void main(String[] args) { Person3 person = new Person3("zhang",20); Print3 print = new Print3(person); Syst3 syst = new Syst3(person); Thread thread1 = new Thread(print); Thread thread2 = new Thread(syst); thread1.start(); thread2.start(); } } class Person3{ int i = 1; String name; int age; boolean flag = false;//用于执行唤醒等待的切换 Lock lock = new ReentrantLock();//至关于synchronized 他有lock()和unlock()方法 Condition preCon = lock.newCondition();//有await()等待和signal()唤醒方法 Condition sysCon = lock.newCondition(); public Person3(String name, int age) { this.name = name; this.age = age; } public void getData(){ try { lock.lock(); while (flag==false){ try { preCon.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+" " +"name:"+name+"age:"+age); flag = !flag; sysCon.signal(); }finally { lock.unlock(); } } public void setData(){ try { lock.lock(); while (flag==true){ try { sysCon.await(); } catch (InterruptedException e) { e.printStackTrace(); } } if(i%2==0){ name = "zhang"; age = 19; }else{ name = "li"; age = 20; } i = i+1; flag = !flag; preCon.signal(); }finally { lock.unlock(); } } } class Print3 implements Runnable{ int i = 1; Person3 person; public Print3(Person3 person) { this.person = person; } @Override public void run() { while (true){ person.setData(); } } } class Syst3 implements Runnable{ Person3 person ; public Syst3(Person3 person) { this.person = person; } @Override public void run() { while (true){ person.getData(); } } }