个人对于Java线程+synchronized+单例模式的一些思考和尝试

这段时间在项目中遇到了线程线程锁以及单例模式的问题,就自己学习了一下,并在此把自己理解和学习的东西总结一下。

做了以下尝试

首先,这里只是使用synchronized修饰了代码段,听说还可以修饰变量和类,这个以后尝试了再更新他们的使用和区别

其次,我也不是特别确定我这里使用的synchronized是不是叫做真正的线程锁。个人理解为,他是限制一段代码或者一些资源,在同一时间只能被一个计算使用。

1、单例的实体类Apple,和他的操作类AppleOperater 使用synchronized关键字

//此处创建一个单例的Apple
public class Apple {
	private Apple() {
		count = 0;
	}
	public int count;
	private static Apple singleApple = null;
	
	public static Apple getInstance() {
		if(singleApple == null) {
			singleApple = new Apple();
		}
		return singleApple;
	}
	
	public int getCount() {
		return this.count;
	}
	
	public void addOne() {
		this.count++;
	}
	
}
public class AppleOperater implements Runnable{
	private Apple apple = Apple.getInstance();
	
	
	public void run() {
		synchronized (apple) {
			
			for(int i=0;i<10;i++) {
				apple.addOne();
				System.out.println(Thread.currentThread().getName() + ":" + apple.getCount());
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

然后再main函数中测试,首先让两个线程跑一个AppleOperater。

public class Demo {
	public static void main(String[] args) {
		AppleOperater appleOperater1= new AppleOperater();
		Thread thread1 = new Thread(appleOperater1,"apple1");
		Thread thread2 = new Thread(appleOperater1,"apple2");
		thread1.start();
		thread2.start();
	}
}

结果如下图。可见是两个线程同时对一个apple进行操作。个人理解为:

可以想象为两个人向一个篮子里放苹果的操作,但是篮子同时只能由一个人持有,所以是apple1先放,apple1把活干完了,appl2在干。


而后,我又尝试了用两个线程分别跑两个AppleOperater,也就是将main函数改为下面这样

public class Demo {
	public static void main(String[] args) {
		AppleOperater appleOperater1= new AppleOperater();
		AppleOperater appleOperater2= new AppleOperater();
		Thread thread1 = new Thread(appleOperater1,"apple1");
		Thread thread2 = new Thread(appleOperater2,"apple2");
		thread1.start();
		thread2.start();
	
	}
}

得到的结果如下图所示,可见效果相同。


2、非单例的Peach类 在PeachOperater中使用synchronized关键字

Peach

public class Peach {
	public int count =0;
	public void addOne() {
		this.count++;
	}
	public int getCount() {
		return this.count;
	}
}
PeachOperater代码如下
public class PeachOperater implements Runnable{
	private Peach peach = new Peach();
	
	public void run() {
		synchronized(peach) {
			for(int i=0;i<10;i++) {
				peach.addOne();
				System.out.println(Thread.currentThread().getName() + ":" + peach.getCount());
			}
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public int getPeachCount() {
		return peach.getCount();
	}
	
}

首先两个线程跑一个PeachOperater,

public class Demo {
	public static void main(String[] args) {
		PeachOperater peachOperater1 = new PeachOperater();
		PeachOperater peachOperater2 = new PeachOperater();
		Thread thread1 = new Thread(peachOperater1,"peach1");
		Thread thread2 = new Thread(peachOperater1,"peach2");
		thread1.start();
		thread2.start();
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程1最终的总数为: " + peachOperater1.getPeachCount());
		System.out.println("线程2最终的总数为: " + peachOperater1.getPeachCount());
	}
}

结果如下,可见,线程1先使用被synchronized修饰的代码,然后线程2在使用。


然后在尝试两个线程分别跑两个PeachOperater,

public class Demo {
	public static void main(String[] args) {
		PeachOperater peachOperater1 = new PeachOperater();
		PeachOperater peachOperater2 = new PeachOperater();
		Thread thread1 = new Thread(peachOperater1,"peach1");
		Thread thread2 = new Thread(peachOperater2,"peach2");
		thread1.start();
		thread2.start();
		
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程1最终的总数为: " + peachOperater1.getPeachCount());
		System.out.println("线程2最终的总数为: " + peachOperater2.getPeachCount());
	}
}

结果如下,可见其相互独立,并且计算结果无误,因为这里只是用synchronized修饰了代码段,并没有影响两个线程之间的数据的独立性,就像这个代码段是个工具,两个线程每次只能一个人使用,俩人随机(还不确定这里的分配机制)的换着用。


3、此处再尝试一下,使用单例模式,但是不使用synchronized关键字

AppleOperater代码如下

public class AppleOperater implements Runnable{
	private Apple apple = Apple.getInstance();
	
	
	public void run() {
		//synchronized (apple) {
			
			for(int i=0;i<10;i++) {
				apple.addOne();
				System.out.println(Thread.currentThread().getName() + ":" + apple.getCount());
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			//}
		}
	}
	
	public int getAppleCount() {
		return this.apple.getCount();
	}
	
}

首先,当两个线程跑一个AppleOperater的时候。main函数更改为

public class Demo {
	public static void main(String[] args) {
		AppleOperater appleOperater1= new AppleOperater();
		AppleOperater appleOperater2= new AppleOperater();
		Thread thread1 = new Thread(appleOperater1,"peach1");
		Thread thread2 = new Thread(appleOperater1,"peach2");
		thread1.start();
		thread2.start();
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("最终的总数为: " + appleOperater1.getAppleCount());
	}
}

其结果如下图所示,可见这样是有问题的,中间的过程不对,输出结果也不对。(具体准确的原因尚不清楚),并且多次尝试后结果不稳定,综述为17、18、19、20的情况都出现过。


然后,进行两个线程跑两个AppleOperater,main函数更改为

public class Demo {
	public static void main(String[] args) {
		AppleOperater appleOperater1= new AppleOperater();
		AppleOperater appleOperater2= new AppleOperater();
		//PeachOperater peachOperater1 = new PeachOperater();
		//PeachOperater peachOperater2 = new PeachOperater();
		Thread thread1 = new Thread(appleOperater1,"peach1");
		Thread thread2 = new Thread(appleOperater2,"peach2");
		thread1.start();
		thread2.start();
		
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程1最终的总数为: " + appleOperater1.getAppleCount());
		System.out.println("线程2最终的总数为: " + appleOperater2.getAppleCount());
	}
}

输出结果如图,同样,中间过程不对,最终结果也不对,且最终结果不稳定,17、18、19、20都会出现。


4、非单例模式,然后也不使用synchronized关键字

public class PeachOperater implements Runnable{
	private Peach peach = new Peach();
	
	public void run() {
		for(int i=0;i<10;i++) {
			peach.addOne();
			System.out.println(Thread.currentThread().getName() + ":" + peach.getCount());
		}
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

在main函数中进行测试,首先用两个线程跑一个PeachOperater。

public class Demo {
	public static void main(String[] args) {
		PeachOperater peachOperater1 = new PeachOperater();
		PeachOperater peachOperater2 = new PeachOperater();
		Thread thread1 = new Thread(peachOperater1,"peach1");
		Thread thread2 = new Thread(peachOperater1,"peach2");
		thread1.start();
		thread2.start();
		try {//这个try/catch段的作用是等待线程执行完毕之后在执行后面的操作
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("最终的总数为: " + peachOperater1.getPeachCount());
	}
}

结果如下图,可见,这种情况的中间结果有些混乱,而且有错误,但是最终总数没错(插不上图了,贴的结果),也不是很清楚为什么中间过程不对,但是最终结果正确。

peach2:2
peach1:2
peach2:3
peach1:4
peach2:5
peach1:6
peach2:7
peach1:8
peach2:9
peach1:10
peach2:11
peach1:12
peach2:13
peach2:15
peach1:14
peach2:16
peach1:17
peach2:18
peach1:19
peach1:20
最终的总数为: 20

然后再用两个线程跑两个PeachOperater,

public class Demo {
	public static void main(String[] args) {
		PeachOperater peachOperater1 = new PeachOperater();
		PeachOperater peachOperater2 = new PeachOperater();
		Thread thread1 = new Thread(peachOperater1,"peach1");
		Thread thread2 = new Thread(peachOperater2,"peach2");
		thread1.start();
		thread2.start();
		
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

结果如下,可见,在这个代码中,线程1和线程2相互独立,其中进行的操作和数据互不影响。

总结:

这里欠一个总结,等回头总结思考了在写


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值