线程同步问题分析
发布日期:2021-06-30 17:51:03 浏览次数:5 分类:技术文章

本文共 4178 字,大约阅读时间需要 13 分钟。

我们先看一个例子:

1、三个线程同时执行一个对象中的run方法。我的想法是卖100张票,当ticket =< 0的时候,就不再卖票了,也就是ticket不再减少了。但是运行结果非常奇怪。

package com.huai.test;public class ThreadTest1 implements Runnable {	private int ticket = 5;	public ThreadTest1() {	}	@Override	public  void run() {		if (ticket > 0) {			try {				Thread.sleep(1000);			} catch (InterruptedException e) {				e.printStackTrace();			}			System.out.println(Thread.currentThread().getName()					+ " selling  ticket : " + ticket--);		}	}	public static void main(String[] args) {		ThreadTest1 t1 = new ThreadTest1();		Thread th1 = new Thread(t1, "a");		Thread th2 = new Thread(t1, "b");		Thread th3 = new Thread(t1, "c");		Thread th4 = new Thread(t1, "d");		Thread th5 = new Thread(t1, "e");		th1.start();		th2.start();		th3.start();		th4.start();		th5.start();	}}

运行的结果(非常奇怪),正确的结果应该是:5,4,3,2,1这样的顺序
a selling  ticket : 5d selling  ticket : 2c selling  ticket : 2e selling  ticket : 3b selling  ticket : 4
之所以有这样的结果,是因为多个线程共享同一个对象。

问题解决:使用同步代码块或者同步方法。

2、同步代码块

我只在定义方法的地方加上了synchronized关键字

package com.huai.test;public class ThreadTest1 implements Runnable {	private int ticket = 5;	public ThreadTest1() {	}	@Override	public synchronized void run() {		if (ticket > 0) {			try {				Thread.sleep(1000);			} catch (InterruptedException e) {				e.printStackTrace();			}			System.out.println(Thread.currentThread().getName()					+ " selling  ticket : " + ticket--);		}	}	public static void main(String[] args) {		ThreadTest1 t1 = new ThreadTest1();		Thread th1 = new Thread(t1, "a");		Thread th2 = new Thread(t1, "b");		Thread th3 = new Thread(t1, "c");		Thread th4 = new Thread(t1, "d");		Thread th5 = new Thread(t1, "e");		th1.start();		th2.start();		th3.start();		th4.start();		th5.start();	}}
结果为:(注意:这里的线程名字的排列顺序是不确定的,谁先抢到cup资源谁就先运行)

a selling  ticket : 5e selling  ticket : 4d selling  ticket : 3c selling  ticket : 2b selling  ticket : 1

3、同步块

 在run方法里面加上synchronized (this) {}

package com.huai.test;public class ThreadTest1 implements Runnable {	private int ticket = 5;	public ThreadTest1() {	}	@Override	public void run() {		synchronized (this) {			if (ticket > 0) {				try {					Thread.sleep(1000);				} catch (InterruptedException e) {					e.printStackTrace();				}				System.out.println(Thread.currentThread().getName()						+ " selling  ticket : " + ticket--);			}		}			}	public static void main(String[] args) {		ThreadTest1 t1 = new ThreadTest1();		Thread th1 = new Thread(t1, "a");		Thread th2 = new Thread(t1, "b");		Thread th3 = new Thread(t1, "c");		Thread th4 = new Thread(t1, "d");		Thread th5 = new Thread(t1, "e");		th1.start();		th2.start();		th3.start();		th4.start();		th5.start();	}}
结果

a selling  ticket : 5d selling  ticket : 4e selling  ticket : 3c selling  ticket : 2b selling  ticket : 1

补充:当一个对象Object 1在不同的线程中执行这个同步方法时,他们(同一个实例里的同步方法们)之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象Object 2却能够任意调用这个被加了synchronized关键字的方法。

我们用实例说话

package com.huai.test;public class ThreadTest1 implements Runnable {	private int ticket = 5;	public ThreadTest1() {	}	@Override	public void run() {		synchronized (this) {			if (ticket > 0) {				try {					Thread.sleep(1000);				} catch (InterruptedException e) {					e.printStackTrace();				}				System.out.println(Thread.currentThread().getName()						+ " selling  ticket : " + ticket--);			}		}			}	public static void main(String[] args) {		ThreadTest1 t1 = new ThreadTest1();		Thread th1 = new Thread(t1, "a ");		Thread th2 = new Thread(t1, "b ");		Thread th3 = new Thread(t1, "c ");		Thread th4 = new Thread(t1, "d ");		Thread th5 = new Thread(t1, "e ");		th1.start();		th2.start();		th3.start();		th4.start();		th5.start();				ThreadTest1 t21 = new ThreadTest1();		Thread th21 = new Thread(t21, "a2");		Thread th22 = new Thread(t21, "b2");		Thread th23 = new Thread(t21, "c2");		Thread th24 = new Thread(t21, "d2");		Thread th25 = new Thread(t21, "e2");		th21.start();		th22.start();		th23.start();		th24.start();		th25.start();	}}
结果:

从结果可以看出,对象t1 和对象t21 在同步上面是各自不影响的。但是在同一个对象上面是不共享的。

a  selling  ticket : 5a2 selling  ticket : 5d  selling  ticket : 4d2 selling  ticket : 4e2 selling  ticket : 3e  selling  ticket : 3c  selling  ticket : 2b2 selling  ticket : 2c2 selling  ticket : 1b  selling  ticket : 1

转载地址:https://liangyihuai.blog.csdn.net/article/details/48954109 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:java线程模拟生产者消费者问题
下一篇:java nio Selector (新IO)分析

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月15日 11时40分16秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章