java多线程一直是学会java的关键,多线程中的同步则是安全性的保障,尽管效率会有所下降。为了理解synchronized 的用法,先把代码放上来
未使用synchronized关键字的代码
package thread; public class ticket implements Runnable{ public int i=10; public void run() { while(true) { if(i>0) { System.out.println(Thread.currentThread().getName()+":卖出一张票,当前还有:"+--i); } try { Thread.sleep(300); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } public static void main(String[] args) { ticket t=new ticket(); for(int i=0;i<2;i++) { Thread s=new Thread(t,"线程"+(i+1)); s.start(); } } }这一段没有使用同步块会产生一定的问题: 线程1:卖出一张票,当前还有:8 线程2:卖出一张票,当前还有:9 线程2:卖出一张票,当前还有:7 线程1:卖出一张票,当前还有:7 线程1:卖出一张票,当前还有:6 线程2:卖出一张票,当前还有:5 线程2:卖出一张票,当前还有:4 线程1:卖出一张票,当前还有:3 线程2:卖出一张票,当前还有:2 线程1:卖出一张票,当前还有:1 线程1:卖出一张票,当前还有:0 线程2:卖出一张票,当前还有:0 或者是 线程1:卖出一张票,当前还有:9 线程2:卖出一张票,当前还有:8 线程1:卖出一张票,当前还有:7 线程2:卖出一张票,当前还有:6 线程1:卖出一张票,当前还有:5 线程2:卖出一张票,当前还有:5 线程1:卖出一张票,当前还有:4 线程2:卖出一张票,当前还有:3 线程1:卖出一张票,当前还有:2 线程2:卖出一张票,当前还有:2 线程2:卖出一张票,当前还有:1 线程1:卖出一张票,当前还有:1 线程1:卖出一张票,当前还有:0 线程2:卖出一张票,当前还有:-1 会出现一张票进行了多次出售或者是把第零张票也卖了,这是因为线程的并发所产生的问题,两个线程同时进行了,我们要做的就是一个线程执行时,其他线程要进行等待,需要用到synchronized 关键字
下面添加同步块来解决这个问题
package thread; public class ticket implements Runnable{ public int i=200; private Object obj=new Object(); public void run() { while(true) { //将线程执行的语句用synchronized关键字包括,并添加同步锁 synchronized (obj) { if(i>0) { System.out.println(Thread.currentThread().getName()+":卖出一张票,当前还有:"+--i); } try { Thread.sleep(500); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } } public static void main(String[] args) { ticket t=new ticket(); for(int i=0;i<4;i++) { Thread s=new Thread(t,"线程"+(i+1)); s.start(); } } }synchronized 这里用的是同步代码块,要为这个关键字设定一个同步锁,这个锁是可以任意的,但是要是这几个线程所共有的,所以我声明了一个object对象。
添加同步方法
package thread; public class ticket implements Runnable{ public int i=200; private Object obj=new Object(); public void run() { while(true) { sell(); } } private synchronized void sell() { if(i>0) { System.out.println(Thread.currentThread().getName()+":卖出一张票,当前还有:"+--i); } try { Thread.sleep(500); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } public static void main(String[] args) { ticket t=new ticket(); for(int i=0;i<4;i++) { Thread s=new Thread(t,"线程"+(i+1)); s.start(); } } }把线程所要执行的代码进行封装,再用synchronized关键字修饰该函数(默认同步锁是this),最后再调用即可 由于我电脑cpu原因,要五百张票才能体现出线程,所以就不放结果了
synchronized修饰不论是同步块还是同步方法,只要有一个线程正在执行,那么这一部分就会锁死,不会出现线程并发的问题。