这一章节接着上一章节最后的错误的思路,我们来证明使用整数属性域作为多线程监视器是不同步的。
1.用同一个属性域作为多线程监视器,是不同步的
package com.ray.deepintothread.ch02.topic_16;
/**
*
* @author RayLee
*
*/
public class DirtyReadWithSynchBlock {
public static void main(String[] args) throws InterruptedException {
MyService2 myService = new MyService2();
ThreadThree threadThree = new ThreadThree(myService);
Thread thread = new Thread(threadThree);
thread.start();
ThreadFour threadFour = new ThreadFour(myService);
Thread thread2 = new Thread(threadFour);
thread2.start();
}
}
class ThreadThree implements Runnable {
private MyService2 myService;
public ThreadThree(MyService2 myService) {
this.myService = myService;
}
@Override
public void run() {
try {
myService.updateA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadFour implements Runnable {
private MyService2 myService;
public ThreadFour(MyService2 myService) {
this.myService = myService;
}
@Override
public void run() {
try {
myService.updateB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyService2 {
private Integer id = 0;
public void updateA() throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(50);
}
}
}
public void updateB() throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(100);
}
}
}
}
输出:
Thread-0 0
Thread-1 1
Thread-0 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 5
Thread-1 6
Thread-1 7
从上面的输出可以得出相应结论
另一个例子:
package com.ray.deepintothread.ch02.topic_16;
/**
*
* @author RayLee
*
*/
public class DirtyReadWithSynchBlock {
public static void main(String[] args) throws InterruptedException {
MyService2 myService = new MyService2();
ThreadThree threadThree = new ThreadThree(myService);
Thread thread = new Thread(threadThree);
thread.setName("thread A");
thread.start();
ThreadFour threadFour = new ThreadFour(myService);
Thread thread2 = new Thread(threadFour);
thread2.setName("thread B");
thread2.start();
}
}
class ThreadThree implements Runnable {
private MyService2 myService;
public ThreadThree(MyService2 myService) {
this.myService = myService;
}
@Override
public void run() {
try {
myService.updateA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadFour implements Runnable {
private MyService2 myService;
public ThreadFour(MyService2 myService) {
this.myService = myService;
}
@Override
public void run() {
try {
myService.updateB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyService2 {
private Integer id = 0;
public void updateA() throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println("id:" + id);
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(50);
System.out.println("-------------------");
}
}
}
public void updateB() throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println("id:" + id);
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(100);
System.out.println("-------------------");
}
}
}
}
输出:
id:0
thread A 0
id:1
thread B 1
-------------------
id:2
thread A 2
-------------------
id:3
thread A 3
-------------------
id:4
thread B 4
-------------------
id:5
thread A 5
-------------------
-------------------
id:6
id:6
thread B 6
thread A 7
-------------------
-------------------
id:8
thread B 8
-------------------
id:9
thread B 9
-------------------
从输出的结果,特别看到中间的id=6的时候,threadA和threadB计算的结果,就不言而喻了。
2.伪synchronized (newobject())同步的例子
package com.ray.deepintothread.ch02.topic_16;
/**
*
* @author RayLee
*
*/
public class SynchBlock {
public static void main(String[] args) throws InterruptedException {
MyService myService = new MyService();
int id = 1;
ThreadOne threadOne = new ThreadOne(myService, id);
Thread thread = new Thread(threadOne);
thread.start();
ThreadTwo threadTwo = new ThreadTwo(myService, id);
Thread thread2 = new Thread(threadTwo);
thread2.start();
}
}
class ThreadOne implements Runnable {
private MyService myService;
private int id = 0;
public ThreadOne(MyService myService, int id) {
this.myService = myService;
this.id = id;
}
@Override
public void run() {
try {
myService.updateA(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadTwo implements Runnable {
private MyService myService;
private int id = 0;
public ThreadTwo(MyService myService, int id) {
this.myService = myService;
this.id = id;
}
@Override
public void run() {
try {
myService.updateB(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyService {
public void updateA(Integer id) throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(50);
}
}
}
public void updateB(Integer id) throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(100);
}
}
}
}
输出:
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
看上去上面的结果是同步的,而且看上去,我们也是对于同一个属性域进行同步访问和修改,但是,其实不是的。
我们上面的步骤如下:
(1)赋值给每一个线程的id
(2)多线程进行访问与修改
实际上我们一直访问和修改的是线程对象里面的id,而不是在main里面的id,我们将上面的代码简化,然后大家再看看
package com.ray.deepintothread.ch02.topic_16;
/**
*
* @author RayLee
*
*/
public class SynchBlock2 {
public static void main(String[] args) throws InterruptedException {
MyService3 myService = new MyService3();
ThreadFive threadFive = new ThreadFive(myService);
Thread thread = new Thread(threadFive);
thread.start();
ThreadSix threadSix = new ThreadSix(myService);
Thread thread2 = new Thread(threadSix);
thread2.start();
}
}
class ThreadFive implements Runnable {
private MyService3 myService;
private int id = 1;
public ThreadFive(MyService3 myService) {
this.myService = myService;
}
@Override
public void run() {
try {
myService.updateA(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadSix implements Runnable {
private MyService3 myService;
private int id = 1;
public ThreadSix(MyService3 myService) {
this.myService = myService;
}
@Override
public void run() {
try {
myService.updateB(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyService3 {
public void updateA(Integer id) throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(50);
}
}
}
public void updateB(Integer id) throws InterruptedException {
synchronized (id) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + id++);
Thread.sleep(100);
}
}
}
}
输出:
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
输出结果跟上面的没有区别,因此,得出结论是,方法里面修改的是每一个线程对象里面的id,是两个不同的属性域,这当然不会出现脏读的情况。
总结:这一章节我们证明了使用整数属性域作为多线程监视器是不同步的。
这一章节就到这里,谢谢
------------------------------------------------------------------------------------
我的github:https://github.com/raylee2015/DeepIntoThread
目录:http://blog.youkuaiyun.com/raylee2007/article/details/51204573