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修饰不论是同步块还是同步方法,只要有一个线程正在执行,那么这一部分就会锁死,不会出现线程并发的问题。