1.1、synchronized方法的弊端

package commonutils;

public class CommonUtils {

    public static long beginTime1;
public static long endTime1; public static long beginTime2;
public static long endTime2;
} =============================
package mytask; import commonutils.CommonUtils; public class Task { private String getData1;
private String getData2; public synchronized void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep(3000);
getData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
getData2 = "长时间处理任务后从远程返回的值2 threadName="
+ 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 mythread; import commonutils.CommonUtils; import mytask.Task; 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 mythread; import commonutils.CommonUtils; import mytask.Task; 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 test;

import mytask.Task;
import mythread.MyThread1;
import mythread.MyThread2; import commonutils.CommonUtils; 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));
}
}

输出结果:

begin task
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
end task
耗时:6

当把同步方法改为同步代码块时,

package mytask;

import commonutils.CommonUtils;

public class Task {

    private String getData1;
private String getData2; public void doLongTimeTask() {
synchronized(Task.class){
try {
System.out.println("begin task");
Thread.sleep(3000);
getData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
getData2 = "长时间处理任务后从远程返回的值2 threadName="
+ 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();
}
} }
}

输出结果:

begin task
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
end task
耗时:6

可见,并没有提升效率,这是因为锁定的范围比较广,所以效果和锁方法的差别并不是太。那么可以缩小边界区,也就是资源真正开始竞争的地方。因为类中的成员变量才是资源的竞争对象,所以需要在访问这些变量的地方进行锁定。那么代码改为如下:

package mytask;

import commonutils.CommonUtils;

public class Task {

    private String getData1;
private String getData2; public void doLongTimeTask() { try {
System.out.println("begin task");
Thread.sleep(3000);
getData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
getData2 = "长时间处理任务后从远程返回的值2 threadName="
+ Thread.currentThread().getName();
synchronized(Task.class){
System.out.println(getData1);
System.out.println(getData2);
}
System.out.println("end task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

输出结果:

begin task
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
end task
耗时:3

这时候可以看到时间已经减小了,这就出现一部分同步,一部分异步了。如何验证是真的一半同步一半异步呢?

package mytask;

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));
}
} }
}

输出结果:

=================================非同步块异步执行
nosynchronized threadName=Thread-0 i=1
nosynchronized threadName=Thread-1 i=1
nosynchronized threadName=Thread-0 i=2
nosynchronized threadName=Thread-1 i=2
nosynchronized threadName=Thread-0 i=3
nosynchronized threadName=Thread-1 i=3
nosynchronized threadName=Thread-0 i=4
nosynchronized threadName=Thread-1 i=4
nosynchronized threadName=Thread-0 i=5
nosynchronized threadName=Thread-1 i=5
nosynchronized threadName=Thread-0 i=6
nosynchronized threadName=Thread-1 i=6
nosynchronized threadName=Thread-0 i=7
nosynchronized threadName=Thread-1 i=7
nosynchronized threadName=Thread-0 i=8
nosynchronized threadName=Thread-1 i=8
=================================同步块同步执行
synchronized threadName=Thread-1 i=85
synchronized threadName=Thread-1 i=86
synchronized threadName=Thread-1 i=87
synchronized threadName=Thread-1 i=88
synchronized threadName=Thread-1 i=89
synchronized threadName=Thread-1 i=90
synchronized threadName=Thread-1 i=91
synchronized threadName=Thread-1 i=92
synchronized threadName=Thread-1 i=93
synchronized threadName=Thread-1 i=94
synchronized threadName=Thread-1 i=95
synchronized threadName=Thread-1 i=96
synchronized threadName=Thread-1 i=97
synchronized threadName=Thread-1 i=98
synchronized threadName=Thread-1 i=99
synchronized threadName=Thread-1 i=100
synchronized threadName=Thread-0 i=1
synchronized threadName=Thread-0 i=2
synchronized threadName=Thread-0 i=3
synchronized threadName=Thread-0 i=4
synchronized threadName=Thread-0 i=5
synchronized threadName=Thread-0 i=6
synchronized threadName=Thread-0 i=7
synchronized threadName=Thread-0 i=8
synchronized threadName=Thread-0 i=9
synchronized threadName=Thread-0 i=10
synchronized threadName=Thread-0 i=11
synchronized threadName=Thread-0 i=12
synchronized threadName=Thread-0 i=13
synchronized threadName=Thread-0 i=14
synchronized threadName=Thread-0 i=15
synchronized threadName=Thread-0 i=16

java多线程基本概述(三)——同步块的更多相关文章

  1. java多线程中的三种特性

    java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...

  2. Java多线程学习(三)volatile关键字

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79680693 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

  3. Java多线程——线程之间的同步

    Java多线程——线程之间的同步 摘要:本文主要学习多线程之间是如何同步的,如何使用volatile关键字,如何使用synchronized修饰的同步代码块和同步方法解决线程安全问题. 部分内容来自以 ...

  4. Java多线程之线程的同步

    Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...

  5. 如何实现有返回值的多线程 JAVA多线程实现的三种方式

    可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口.执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable ...

  6. Java 多线程基础(三) start() 和 run()

    Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...

  7. java多线程二之线程同步的三种方法

          java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...

  8. java 多线程: Thread 并发访问-代码块同步synchronized {};String作为被锁的对象

    方法同步的弊端 方法同步的时候,如果一个方法需要线程安全控制的代码速度其实很快,但是还有其他的业务逻辑代码耗时非常长(比如网络请求),这样所有的线程就在这一块就等待着了,这样造成了极大的资源浪费如果并 ...

  9. java多线程基本概述(三)——同步方法

    非线程安全其实是在多个线程对同一个对象实例的变量进行并发访问的时候发生,产生的后果就是脏读,也就是取到的数据是修改过的.而线程安全就是获得的实例变量的值是经过同步处理的,从而不会出现脏读现象. 1.1 ...

随机推荐

  1. Jenkins+Git 持续集成

    持续集成是必要的! 希望达到的效果是:开发同事签入代码后,对应的站点可以自动实现更新.目前还只在在内部服务器上实现开发环境中的站点更新,不涉及到线上的发布. 目前使用Jenkins实现这样的持续集成. ...

  2. Objective-C日记-之编码对象属性

    NSCoder类 1,概述 将对象的实例变量和其他数据编码为数据块,然后将他们存在到磁盘当中:以后将这些数据块读回到内存中,并且还基于保存的数据创建新的对象,也称序列化或反序列化. 2,用法 a,首先 ...

  3. Hibernate优缺点

    下面就Hibernate优缺点分别进行简单的阐述.1.Hibernate优点:(1)对象/关系数据库映射(Basic O/R Mapping)它使用时只需要操纵对象,使开发更对象化,抛弃了数据库中心的 ...

  4. 1611: [Usaco2008 Feb]Meteor Shower流星雨

    1611: [Usaco2008 Feb]Meteor Shower流星雨 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1010  Solved: 44 ...

  5. JavaScript 基础阶段测试题

    JavaScript 基础阶段测试题,试试你能得多少分? 一.选择题1.分析下段代码输出结果是( )    var arr = [2,3,4,5,6];    var sum =0;    for(v ...

  6. Hibernate写配置文件无提示信息解决

    把Hibernate的相关jar包引入工程后,在配置hibernate.cfg.xml时没有提示信息,对于开发人员来说,那么多标签,标签有那么多属性,全部都记住显然是不可能的,遇到这种情况是很头疼的事 ...

  7. C语言sqrt函数

    引入头文件: # include <math.h> sqrt用来求给定值的平方根 double sqrt (double x) 在使用GCC编译时 加入 -lm参数

  8. ios 个推推送集成

    个推推送总结: 个推第三方平台官网地址:http://www.getui.com/cn/index.html 首先去官网注册账号,创建应用,应用的配置信息,创建APNs推送证书上传 P12证书(开发对 ...

  9. iOS 组件化

    iOS 组件化介绍 随着应用需求逐步迭代,应用的代码体积将会越来越大,为了更好的管理应用工程,我们开始借助CocoaPods版本管理工具对原有应用工程进行拆分.但是仅仅完成代码拆分还不足以解决业务之间 ...

  10. 获取 metadata 过程详解 - 每天5分钟玩转 OpenStack(167)

    接上节,启动 neutron router 后 instance c1 终于拿到了 metadata, 从下面 c1 的启动日志可知: c1 所认为的 metadata 服务地址是 169.254.1 ...