多线程简单实例真的需要synchronized么?
Posted torjan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程简单实例真的需要synchronized么?相关的知识,希望对你有一定的参考价值。
说道多线程的安全问题,很多人想到就就是加锁。用到synchronized关键字。
那就要先说说synchronized问什么能够保证线程安全了。
首先要了解线程的工作方式:线程工作分为工作内存和主内存。主内存就是堆和静态区。当线程运行时,首先将主内存的数据拿到工作内存
然后在工作内存中运行,再将数据写回主内存。工作内存是私有的,但是主内存却是共享的。
那么线程不安全的主要根源就是不能线程读写主内存的共享数据。
那么判断要不要加锁,在什么位置加锁就有了依据——共享数据
下面看一个例子:
package code.thread; public class SynchronizedDome extends Thread{ int a = 0; Object obj = new Object(); @Override public void run() { synchronized(obj) { for(int i=5;i>0;i--){ System.out.println(a); a++; try { Thread.sleep(0); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { SynchronizedDome dome = new SynchronizedDome(); SynchronizedDome dome2 = new SynchronizedDome(); SynchronizedDome dome3 = new SynchronizedDome(); System.out.println("Thread start:"); dome.start(); dome2.start(); dome3.start(); } }
执行结果:
Thread start:
0
1
0
0
2
3
1
1
2
3
4
4
2
3
4
看到没,并没有发生错乱,与预想的输出结果一致
那么你可能会说,这是synchronized的功劳。真的是这样的么,稍微改动过一下在看看
package code.thread; public class SynchronizedDome extends Thread{ int a = 0; Object obj = new Object(); @Override public void run() { //synchronized(obj) { { for(int i=5;i>0;i--){ System.out.println(a); a++; try { Thread.sleep(0); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { SynchronizedDome dome = new SynchronizedDome(); SynchronizedDome dome2 = new SynchronizedDome(); SynchronizedDome dome3 = new SynchronizedDome(); System.out.println("Thread start:"); dome.start(); dome2.start(); dome3.start(); } }
看到没,还是安全的,并没有因为没加锁而发生错乱
那么我没就要分析一下了,根据我们上面所说的,线程的不安全是因为数据的共享
这个例子中,分别new了三个线程对象。
每个对象在栈上有一个变量a,他们分别属于不同的对象。所以三个线程操作的都是属于自己本身类的数据。是对象私有的。
所以不存在数据的共享,那么就不用加锁了。
我没在看一个例子,让他们数据共享,将变量定义为静态变量
package code.thread; public class SynchronizedDome2 { public static void main(String[] args) { Dome dome = new Dome(); Thread thread = new Thread(dome); Thread thread2 = new Thread(dome); thread.start(); thread2.start(); } } class Dome implements Runnable { static int a = 0; @Override public void run() { //synchronized(this){ { for(int i=0;i<5;i++) { System.out.println(Thread.currentThread().getName()+": "+a++); } } } }
输出结果:
Thread-1: 0
Thread-0: 1
Thread-1: 2
Thread-0: 3
Thread-1: 4
Thread-0: 5
Thread-1: 6
Thread-1: 8
Thread-0: 7
Thread-0: 9
这么换乱,而且我们侥幸没有得到错误的结果。如果多运行几次就会看到可能会出现错误的结果
那么下面用锁来解决,看看有什么不同。
程序就是将什么代码加锁注释去掉。
输出结果:
Thread-0: 0
Thread-0: 1
Thread-0: 2
Thread-0: 3
Thread-0: 4
Thread-1: 5
Thread-1: 6
Thread-1: 7
Thread-1: 8
Thread-1: 9
总结:总的来说线程不安全是由于共享数据的读写不同步引起的。当不涉及到共享数据,也就无不安全可说了。
synchronized关键字保证了操作的原子性和可见性。原子性就是说,一个执行步奏完整的执行完毕,不会再执行的过程中被其他线程打断。
可见性是说,当执行完锁定的代码块后,在解锁之前会把最新的数据写入到主内存中。并且清空其他线程工作内存中该数据的值。保证了该数据时最新的。
以上是关于多线程简单实例真的需要synchronized么?的主要内容,如果未能解决你的问题,请参考以下文章