《Java多线程编程核心技术》读后感(三)
synchronized同步语句块
用synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行以一个长时间的任务,那么B线程则必须等待比较较长的时间。在这样的情况下可以使用synchronized同步语句块来解决
synchronized方法的弊端
package Second;
public class Task {
private String getData1;
private String getData2;
public synchronized void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep(3000);
getData1 = "长时间处理任务后从远程返回的值1threadName="
+ Thread.currentThread().getName();
getData2 = "长时间处理任务后从远程返回的值2threadName="
+ Thread.currentThread().getName();
System.out.println(getData1);
System.out.println(getData2);
System.out.println("end task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package Second;
public class CommonUtils {
public static long beginTime1;
public static long endTime1;
public static long beginTime2;
public static long endTime2;
}
package Second;
public class MyThread1 extends Thread {
private Task task;
public MyThread1(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}
package Second;
public class MyThread2 extends Thread {
private Task task;
public MyThread2(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
}
}
package Second;
public class Run {
public static void main(String[] args) {
Task task = new Task();
MyThread1 thread1 = new MyThread1(task);
thread1.start();
MyThread2 thread2 = new MyThread2(task);
thread2.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long beginTime = CommonUtils.beginTime1;
if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
beginTime = CommonUtils.beginTime2;
}
long endTime = CommonUtils.endTime1;
if (CommonUtils.endTime2 > CommonUtils.endTime1) {
endTime = CommonUtils.endTime2;
}
System.out.println("耗时:" + ((endTime - beginTime) / 1000));
}
}

synchronized同步代码块的使用
当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
package Second;
public class ObjectService {
public void serviceMethod() {
try {
synchronized (this) {
System.out.println("begin time=" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("end end=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package Second;
public class ThreadA extends Thread {
private ObjectService service;
public ThreadA(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethod();
}
}
package Second;
public class ThreadB extends Thread {
private ObjectService service;
public ThreadB(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethod();
}
}
package Second;
public class Run {
public static void main(String[] args) {
ObjectService service = new ObjectService();
ThreadA a = new ThreadA(service);
a.setName("a");
a.start();
ThreadB b = new ThreadB(service);
b.setName("b");
b.start();
}
}

虽然使用了同步代码块,但执行的效率还是没有提高
用同步代码块解决同步方法的弊端
package Second;
public class CommonUtils {
public static long beginTime1;
public static long endTime1;
public static long beginTime2;
public static long endTime2;
}
package Second;
public class MyThread1 extends Thread {
private Task task;
public MyThread1(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}
package Second;
public class MyThread2 extends Thread {
private Task task;
public MyThread2(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
}
}
package Second;
public class Task {
private String getData1;
private String getData2;
public void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep(3000);
String privateGetData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
String privateGetData2 = "长时间处理任务后从远程返回的值2 threadName="
+ Thread.currentThread().getName();
synchronized (this) {
getData1 = privateGetData1;
getData2 = privateGetData2;
}
System.out.println(getData1);
System.out.println(getData2);
System.out.println("end task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package Second;
public class MyThread1 extends Thread {
private Task task;
public MyThread1(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}


一半异步,一半同步
package Second;
public class Task {
public void doLongTimeTask() {
for (int i = 0; i < 100; i++) {
System.out.println("nosynchronized threadName="
+ Thread.currentThread().getName() + " i=" + (i + 1));
}
System.out.println("");
synchronized (this) {
for (int i = 0; i < 100; i++) {
System.out.println("synchronized threadName="
+ Thread.currentThread().getName() + " i=" + (i + 1));
}
}
}
}
package Second;
public class MyThread1 extends Thread {
private Task task;
public MyThread1(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
task.doLongTimeTask();
}
}
package Second;
public class MyThread2 extends Thread {
private Task task;
public MyThread2(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
task.doLongTimeTask();
}
}
package Second;
public class Run {
public static void main(String[] args) {
Task task = new Task();
MyThread1 thread1 = new MyThread1(task);
thread1.start();
MyThread2 thread2 = new MyThread2(task);
thread2.start();
}
}


进入代码块后则排队执行
synchronized代码块间的同步性
当一个线程访问object的一个同步代码块时,其他线程对同一个object中所有其他的同步代码块的访问将被阻塞。这说明synchronized使用的时一个“对象监视器”
package Second;
public class ObjectService {
public void serviceMethodA() {
try {
synchronized (this) {
System.out.println("A begin time=" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("A end end=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void serviceMethodB() {
synchronized (this) {
System.out.println("B begin time=" + System.currentTimeMillis());
System.out.println("B end end=" + System.currentTimeMillis());
}
}
}
package Second;
public class ThreadA extends Thread {
private ObjectService service;
public ThreadA(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodA();
}
}
package Second;
public class ThreadB extends Thread {
private ObjectService service;
public ThreadB(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodB();
}
}
package Second;
public class Run {
public static void main(String[] args) {
ObjectService service = new ObjectService();
ThreadA a = new ThreadA(service);
a.setName("a");
a.start();
ThreadB b = new ThreadB(service);
b.setName("b");
b.start();
}
}

两个代码块按顺序执行
验证同步代码块是锁定当前对象的
package Second;
public class Task {
public void otherMethod() {
System.out.println("------------------------run--otherMethod");
}
public void doLongTimeTask() {
synchronized (this) {
for (int i = 0; i < 10000; i++) {
System.out.println("synchronized threadName="
+ Thread.currentThread().getName() + " i=" + (i + 1));
}
}
}
}
package Second;
public class MyThread1 extends Thread {
private Task task;
public MyThread1(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
task.doLongTimeTask();
}
}
package Second;
public class MyThread2 extends Thread {
private Task task;
public MyThread2(Task task) {
super();
this.task = task;
}
@Override
public void run() {
super.run();
task.otherMethod();
}
}
package Second;
public class Run {
public static void main(String[] args) throws InterruptedException {
Task task = new Task();
MyThread1 thread1 = new MyThread1(task);
thread1.start();
Thread.sleep(100);
MyThread2 thread2 = new MyThread2(task);
thread2.start();
}
}

package Second;
public class Task {
synchronized public void otherMethod() {
System.out.println("------------------------run--otherMethod");
}
public void doLongTimeTask() {
synchronized (this) {
for (int i = 0; i < 10000; i++) {
System.out.println("synchronized threadName="
+ Thread.currentThread().getName() + " i=" + (i + 1));
}
}
}
}

实际上,synchronized(this)以及非static的synchronized方法(至于static synchronized方法请往下看),只能防止多个线程同时执行同一个对象的同步代码段。
回到本文的题目上:synchronized锁住的是代码还是对象。答案是:synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也就是this。
参考:https://www.cnblogs.com/QQParadise/articles/5059824.html
《Java多线程编程核心技术》读后感(三)的更多相关文章
- java多线程编程核心技术——第三章
第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...
- java多线程编程核心技术——第三章总结
第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...
- java多线程编程核心技术(三)--线程间通信
1.等待/通知机制 1.wait()方法:使当前执行代码的线程进行等待.wait()方法是Object类的方法,该方法将当前线程放入“预执行队列”中,并在wait()所处的代码行处停止执行.只到被唤起 ...
- Java多线程编程核心技术(三)多线程通信
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...
- Java多线程编程核心技术---学习分享
继承Thread类实现多线程 public class MyThread extends Thread { @Override public void run() { super.run(); Sys ...
- Java多线程编程核心技术
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
- 《Java多线程编程核心技术》推荐
写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点 ...
- Java多线程编程核心技术(二)对象及变量的并发访问
本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...
- Java多线程编程核心技术(一)Java多线程技能
1.进程和线程 一个程序就是一个进程,而一个程序中的多个任务则被称为线程. 进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位. 举个例子: 打开你的计算机上的任务管 ...
- 《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析
不使用等待通知机制 实现线程间通信的 疑问分析 2018年04月03日 17:15:08 ayf 阅读数:33 编辑 <java多线程编程核心技术>一书第三章开头,有如下案例: ...
随机推荐
- iPhone,iPad如何获取WIFI名称即SSID
本文转载至 http://blog.csdn.net/wbw1985/article/details/20530281 2010年开始苹果清理了一批APP Store上的WIFI扫描软件, 缘由语焉 ...
- python 基础 5.1 python 构造器
一. 类的构造器 __init__ 构造函数,在生成对象时调用.由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去.通过定义一个特殊的__init__方法, ...
- TP框架部分---空控制器
<?php namespace Admin\Controller; use Think\Controller; class DengLuController extends Controller ...
- The goroutine scheduler is not preemptive.
go - Why is time.sleep required to run certain goroutines? - Stack Overflow https://stackoverflow.co ...
- mysql一:操作数据库
创建数据库是指在数据库空间中划出一块空间用来存储相关的数据,表就是存储在对应的数据库里面.首先来看下查看数据库的命令:show databases. 这个是用来查询数据库空间下所有的数据库,其中inf ...
- 取得微信用户OpenID
公司需要微信这个平台和用户交流,于是开始研究微信公众平台.微信公众平台分为两种模式,其一是编辑模式,比如用户发什么内容,你可以响应什么内容.另外一种便是开发模式,这个模式功能丰富,不仅仅可以获取到用户 ...
- MySQL 中事务的实现
在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的: 在这篇文章中,我们将对事务的实现进行分析, ...
- American Heritage usaco
基础题,主要思路是找到根,然后分别递归即可: #include<iostream> #include<cstring> #include<string> #incl ...
- 使用python转换编码格式
之前有写过一个使用powershell转换文档格式的方法,然而因为powershell支持不是很全,所以并不好用.这里使用python再做一个. 思路 检测源码格式,如果不是utf8,则进行转换,否则 ...
- jstl <c:url>标签
标签作用是将一个URL地址格式化为一个字符串,并且保存在一个变量当中.它具有URL自动重写功能.value指定的URL可以是当前工程的一个URL地址,也可以是其他web工程的URL.但是这时需要con ...