该关键字的作用:当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
用法是: synchronized(this){/*区块*/},它的作用域是当前对象;
下面使用例子分别解释下面几句话的含义:
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
1.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
3.尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
4.第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
public class pra implements Runnable{
public void run()
{
synchronized(this){
for(int i = 0 ; i<5;i++)
{
System.out.println(Thread.currentThread().getName() + " synchronized loop" + i);
}
}
}
public static void main(String[] args) {
pra t1 = new pra();
Thread ta = new Thread(t1,"A");
Thread tb = new Thread(t1,"B");
ta.start();
tb.start();
}
}
输出结果:
可以发现,线程A在执行完成后,才开始执行线程B。(为什么是先执行A,后执行B呢,就是因为ta.start()在前面,如果ta.start在后面,那么就会先执行线程B,因此看准谁先start也很重要)
如果没有“synchronized”的修饰,那么该方法在执行的时候,AB线程会交错的形式进行。
A synchronized loop0
A synchronized loop1
A synchronized loop2
A synchronized loop3
A synchronized loop4
B synchronized loop0
B synchronized loop1
B synchronized loop2
B synchronized loop3
B synchronized loop4
2. 然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
2.1 一个调用m4t1,()一个调用m4t2()
public class pra{
public void m4t1()
{
synchronized(this)
{
int i = 5;
while(i -- >0)
{
System.out.println(Thread.currentThread().getName()+ " : "+ i);
try
{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
}
public void m4t2()
{
int i = 5;
while(i -- >0)
{
System.out.println(Thread.currentThread().getName()+ " : "+ i);
try
{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
public static void main(String[] args) {
final pra myt2 = new pra();
Thread t1 = new Thread(new Runnable(){public void run() { myt2.m4t1();}},"t1");
Thread t2 = new Thread(new Runnable(){public void run() { myt2.m4t2();}},"t2");
t1.start();
t2.start();
}
}
输出结果:因为1.2两个线程,互补影响,那么谁先被cpu调度就先执行谁。每次运行的结果应该也是不同的
t1 : 4
t2 : 4
t1 : 3
t2 : 3
t1 : 2
t2 : 2
t2 : 1
t1 : 1
t2 : 0
t1 : 0
而且:有人可能有疑问:为什么是(4433221100),是不是两个线程必须这么交错执行。
经过测试,并非如此,如果把m4t1()的输出,改成50,就可以发现,并一定是(49 4 48 3 47 2 ...)这样的
2.2 如果都调用m4t2()函数
public class pra{
public void m4t1()
{
synchronized(this)
{
int i = 5;
while(i -- >0)
{
System.out.println(Thread.currentThread().getName()+ " : "+ i);
try
{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
}
public void m4t2()
{
int i = 5;
while(i -- >0)
{
System.out.println(Thread.currentThread().getName()+ " : "+ i);
try
{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
public static void main(String[] args) {
final pra myt2 = new pra();
Thread t1 = new Thread(new Runnable(){public void run() { myt2.m4t2();}},"t1");
Thread t2 = new Thread(new Runnable(){public void run() { myt2.m4t2();}},"t2");
t1.start();
t2.start();
}
}
输出结果:
注意,如果都是执行m4t2函数,该函数是没有synchronized修饰的,因此线程是看cpu调度来执行。
t2 : 4
t1 : 4
t1 : 3
t2 : 3
t1 : 2
t2 : 2
t1 : 1
t2 : 1
t2 : 0
t1 : 0
2.3 三个线程
public class pra{
public void m4t1()
{
synchronized(this)
{
int i = 5;
while(i -- >0)
{
System.out.println(Thread.currentThread().getName()+ " : "+ i);
try
{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
}
public void m4t2()
{
int i = 5;
while(i -- >0)
{
System.out.println(Thread.currentThread().getName()+ " : "+ i);
try
{
Thread.sleep(500);
}catch(InterruptedException ie){
}
}
}
public static void main(String[] args) {
final pra myt2 = new pra();
Thread t1 = new Thread(new Runnable(){public void run() { myt2.m4t1();}},"t1");
Thread t2 = new Thread(new Runnable(){public void run() { myt2.m4t2();}},"t2");
Thread t3 = new Thread(new Runnable(){public void run() { myt2.m4t1();}},"t3");
t3.start();
t1.start();
t2.start();
}
}
输出结果:
因为3.1都执行有“synchronized”修饰的m4t1(),而且是t3先start,因此t1会等到t3 全部执行完,才开始执行。
t3 : 4
t2 : 4
t3 : 3
t2 : 3
t2 : 2
t3 : 2
t3 : 1
t2 : 1
t3 : 0
t2 : 0
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
public class Thread3 {
class Inner {
private void m4t1() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
private void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
}
private void m4t1(Inner inner) {
synchronized(inner) { //使用对象锁
inner.m4t1();
}
private void m4t2(Inner inner) {
inner.m4t2();
}
public static void main(String[] args) {
final Thread3 myt3 = new Thread3();
final Inner inner = myt3.new Inner();
Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1");
Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2");
t1.start();
t2.start();
}
}
输出结果:
尽管线程t1获得了对Inner的对象锁,但由于线程t2访问的是同一个Inner中的非同步部分。所以两个线程互不干扰。
t1 : Inner.m4t1()=4
t2 : Inner.m4t2()=4
t1 : Inner.m4t1()=3
t2 : Inner.m4t2()=3
t1 : Inner.m4t1()=2
t2 : Inner.m4t2()=2
t1 : Inner.m4t1()=1
t2 : Inner.m4t2()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=0
现在在Inner.m4t2()前面加上synchronized:
private synchronized void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
结果:
尽管线程t1与t2访问了同一个Inner对象中两个毫不相关的部分,但因为t1先获得了对Inner的对象锁,所以t2对Inner.m4t2()的访问也被阻塞,因为m4t2()是Inner中的一个同步方法。
t1 : Inner.m4t1()=4
t1 : Inner.m4t1()=3
t1 : Inner.m4t1()=2
t1 : Inner.m4t1()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=4
t2 : Inner.m4t2()=3
t2 : Inner.m4t2()=2
t2 : Inner.m4t2()=1
t2 : Inner.m4t2()=0
参考:https://blog.csdn.net/ahgaojie451/article/details/50900421