【Java学习】线程的同步-synchronized的理解

时间:2021-08-19 23:34:31

关键字:synchronized +方法  synchronized(对象或this)

多线程比单线程确实更加优秀,然而使用多线程时还是需要注意一些问题,既然有多个线程,那么就会存在多个线程同时访问一个资源的同步问题,上一篇博客里说了,使用实现了Runnable接口的线程可以实现资源的共享,但是,只有共享并不够,如果多个线程操作一个数据,那么数据的限制条件将形同虚设,比如if条件限制a>0,当a=2时,如果是单线程的话,a还可以执行一次操作,然而这次操作有多个进程进入,那么,最后可以得到的a就是负数了,即使有if条件也无济于事!

解决方法:synchronized关键字

synchroized的作用:一般使用synchronized修饰方法或代码块的线程都在同一个监视器管理下,实现线程同步。

完美的解决了上述的问题,首先我们必须知道,其实每一个java对象都有一把内置锁,当代码运行到有synchronized关键字的区域内时,当前进程获得这段代码的锁,那么这段代码就只能当前进程访问,其他进程必须等待当前进程执行完这段代码并释放锁,接着获取了锁的进程继续独占,可以这样记忆:这样的多线程很“单线程”(无疑,使用同步会使得程序变慢,因为多了更多的等待)。 总而言之,synchronized的作用就是获取锁,然后关门,把其他进程锁在外面。

我们再来看看synchronized的用法

synchronized修饰方法

public class TestTicket1 {
public static void main(String[] args) {
// 有两个售票厅
MyTicket ticket1 = new MyTicket();
Thread t1 = new Thread(ticket1, "A");
Thread t2 = new Thread(ticket1, "B");
Thread t3 = new Thread(ticket1, "C");
Thread t4 = new Thread(ticket1, "D");
t1.start();
t2.start();
t3.start();
t4.start();
}
}

class MyTicket implements Runnable {
// 总共有五张票
private int num = 10;

public synchronized void fun() {
if (this.num > 0) {

try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还剩下" + --num + "张票");
}
}

@Override
public void run() {
// TODO Auto-generated method stub
while (num > 0) {
fun();

}

}

}
这里的fun()方法,就是使用synchronized修饰的方法,当某一进程进入该代码时,获取锁

synchronized 代码块

class MyTicket implements Runnable {
// 总共有五张票
private int num = 10;
@Override
public void run() {
// TODO Auto-generated method stub
while (num > 0) {
synchronized(this)
{
if (this.num > 0) {

try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还剩下" + --num + "张票");
}
}


}

}

}

这里使用synchronized(this){}代码块,this代表当前线程;

synchronized代码块和synchronized修饰的方法作用是完全一样的。