《Java多线程编程核心技术》读后感(二)
方法内的变量为线程安全
package Second; public class HasSelfPrivateNum {
public void addI(String username) {
try {
int num = 0;
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package Second; public class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
} @Override
public void run() {
super.run();
numRef.addI("a");
} }
package Second; public class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
} @Override
public void run() {
super.run();
numRef.addI("b");
} }
package Second; public class Run {
public static void main(String[] args) { HasSelfPrivateNum numRef = new HasSelfPrivateNum(); ThreadA athread = new ThreadA(numRef);
athread.start(); ThreadB bthread = new ThreadB(numRef);
bthread.start(); }
}
实例变量非线程安全
如果对象中有多个实例变量,则运行结果有可能出现交叉的情况
如果对象仅有一个变量,则有可能出现覆盖的情况
package Second; public class HasSelfPrivateNum {
private int num = 0;
public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
解决方案:
package Second; public class HasSelfPrivateNum {
private int num = 0;
synchronized public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
实验结论:在两个线程访问同一个对象重点额同步方法时一定是线程安全的
多个对象多个锁
其他代码实现代码如上
package Second; public class Run {
public static void main(String[] args) { HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
HasSelfPrivateNum numRef2 = new HasSelfPrivateNum(); ThreadA athread = new ThreadA(numRef1);
athread.start(); ThreadB bthread = new ThreadB(numRef2);
bthread.start(); }
}
上面例子是两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果却以异步的方式运行的。本实例由于创建了两个业务对象,在系统中产生出两个锁,所以运行结果是异步的
sychronized方法与锁对象
证明前面讲述的线程锁的是对象
package Second; public class MyObject { public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(500000);
System.out.println("end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package Second; public class ThreadA extends Thread { private MyObject object; public ThreadA(MyObject object) {
super();
this.object = object;
} @Override
public void run() {
super.run();
object.methodA();
} }
package Second; public class ThreadB extends Thread { private MyObject object; public ThreadB(MyObject object) {
super();
this.object = object;
} @Override
public void run() {
super.run();
object.methodA();
} }
package Second; public class Run { public static void main(String[] args) {
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadB b = new ThreadB(object);
b.setName("B"); a.start();
b.start();
}
}
package Second; public class MyObject { synchronized public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
调用关键字synchronized声明的方法一定是在排队运行中,另外需要牢牢记住“共享”两个字,只有共享资源的读写访问才需要同步化,如果不是共享资源,就没有同步的必要
package chapter02.section01.thread_2_1_4.project_2_synchronizedMethodLockObject2; public class MyObject { synchronized public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end endTime=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void methodB() {
try {
System.out.println("begin methodB threadName="
+ Thread.currentThread().getName() + " begin time="
+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("end");
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
package chapter02.section01.thread_2_1_4.project_2_synchronizedMethodLockObject2; public class ThreadA extends Thread { private MyObject object; public ThreadA(MyObject object) {
super();
this.object = object;
} @Override
public void run() {
super.run();
object.methodA();
} }
package chapter02.section01.thread_2_1_4.project_2_synchronizedMethodLockObject2; public class ThreadB extends Thread { private MyObject object; public ThreadB(MyObject object) {
super();
this.object = object;
} @Override
public void run() {
super.run();
object.methodB();
}
}
package chapter02.section01.thread_2_1_4.project_2_synchronizedMethodLockObject2; public class Run { public static void main(String[] args) {
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadB b = new ThreadB(object);
b.setName("B"); a.start();
b.start();
} }
虽然线程A先持有了object对象的锁,但线程B完全可以异步调用非synchronized类型的方法
package chapter02.section01.thread_2_1_4.project_2_synchronizedMethodLockObject2; public class MyObject { synchronized public void methodA() {
try {
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end endTime=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
} synchronized public void methodB() {
try {
System.out.println("begin methodB threadName="
+ Thread.currentThread().getName() + " begin time="
+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("end");
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
脏读
发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过了
package Second; public class PublicVar { public String username = "A";
public String password = "AA"; synchronized public void setValue(String username, String password) {
try {
this.username = username;
Thread.sleep(5000);
this.password = password; System.out.println("setValue method thread name=" + Thread.currentThread().getName() + " username="
+ username + " password=" + password);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void getValue() {
System.out.println("getValue method thread name=" + Thread.currentThread().getName() + " username=" + username
+ " password=" + password);
}
}
package Second; public class ThreadA extends Thread { private PublicVar publicVar; public ThreadA(PublicVar publicVar) {
super();
this.publicVar = publicVar;
} @Override
public void run() {
super.run();
publicVar.setValue("B", "BB");
} }
package Second; public class Test { public static void main(String[] args) {
try {
PublicVar publicVarRef = new PublicVar();
ThreadA thread = new ThreadA(publicVarRef);
thread.start(); Thread.sleep(200); publicVarRef.getValue();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
}
出现脏读是因为getValue()并不是同步的,所以可以在任意时候进行调用
package Second; public class PublicVar { public String username = "A";
public String password = "AA"; synchronized public void setValue(String username, String password) {
try {
this.username = username;
Thread.sleep(5000);
this.password = password; System.out.println("setValue method thread name=" + Thread.currentThread().getName() + " username="
+ username + " password=" + password);
} catch (InterruptedException e) {
e.printStackTrace();
}
} synchronized public void getValue() {
System.out.println("getValue method thread name=" + Thread.currentThread().getName() + " username=" + username
+ " password=" + password);
}
}
synchronized锁重入
也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。这也证明在一个synchronized方法/块内的内部调用本类的其他synchronized方法/块时,是用户可以得到锁的。
package Second; public class Service { synchronized public void service1() {
System.out.println("service1");
service2();
} synchronized public void service2() {
System.out.println("service2");
service3();
} synchronized public void service3() {
System.out.println("service3");
} }
package Second; public class MyThread extends Thread {
@Override
public void run() {
Service service = new Service();
service.service1();
} }
package Second; public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}
package Second; public class Main { public int i = 10; synchronized public void operateIMainMethod() {
try {
i--;
System.out.println("main print i=" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
package Second; public class Sub extends Main { synchronized public void operateISubMethod() {
try {
while (i > 0) {
i--;
System.out.println("sub print i=" + i);
Thread.sleep(100);
this.operateIMainMethod();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
package Second; public class MyThread extends Thread {
@Override
public void run() {
Sub sub = new Sub();
sub.operateISubMethod();
} }
package Second; public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
Main main = new Main();
System.out.println(main.i);
}
}
此实验表明,当存在父子类继承关系时,子类是完全可以通过“”可重入锁“”调用父类的同步方法的
出现异常,锁自动释放
当一个线程执行的代码出现异常时,其所持有的锁会自动释放
package Second; public class Service {
synchronized public void testMethod() {
if (Thread.currentThread().getName().equals("a")) {
System.out.println("ThreadName=" + Thread.currentThread().getName()
+ " run beginTime=" + System.currentTimeMillis());
int i = 1;
while (i == 1) {
if (("" + Math.random()).substring(0, 8).equals("0.123456")) {
System.out.println("ThreadName="
+ Thread.currentThread().getName()
+ " run exceptionTime="
+ System.currentTimeMillis());
Integer.parseInt("a");
}
}
} else {
System.out.println("Thread B run Time="
+ System.currentTimeMillis());
}
}
}
package Second; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
} }
package Second ; public class ThreadB extends Thread {
private Service service; public ThreadB(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
} }
package Second; public class Test { public static void main(String[] args) {
try {
Service service = new Service(); ThreadA a = new ThreadA(service);
a.setName("a");
a.start(); Thread.sleep(500); ThreadB b = new ThreadB(service);
b.setName("b");
b.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
线程a出现异常并释放锁,线程b进入方法正常打印
同步不具有继承性
package Second; public class Main { synchronized public void serviceMethod() {
try {
System.out.println("int main 下一步 sleep begin threadName="
+ Thread.currentThread().getName() + " time="
+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("int main 下一步 sleep end threadName="
+ Thread.currentThread().getName() + " time="
+ System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
package Second; public class Sub extends Main { @Override
synchronized public void serviceMethod() {
try {
System.out.println("int sub 下一步 sleep begin threadName="
+ Thread.currentThread().getName() + " time="
+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("int sub 下一步 sleep end threadName="
+ Thread.currentThread().getName() + " time="
+ System.currentTimeMillis());
super.serviceMethod();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
package Second; public class MyThreadA extends Thread { private Sub sub; public MyThreadA(Sub sub) {
super();
this.sub = sub;
} @Override
public void run() {
sub.serviceMethod();
} }
package Second; public class MyThreadB extends Thread { private Sub sub; public MyThreadB(Sub sub) {
super();
this.sub = sub;
} @Override
public void run() {
sub.serviceMethod();
}
}
所以还要在子类的方法中添加synchronized关键字
《Java多线程编程核心技术》读后感(二)的更多相关文章
- Springboot揭秘-快速构建微服务体系-王福强-2016年5月第一次印刷
JavaConfig项目: spring IOC有一个非常核心的概念——Bean.由Spring容器来负责对Bean的实例化,装配和管理.XML是用来描述Bean最为流行的配置方式.Spring可以从 ...
- 《SpringBoot揭秘 快速构建微服务体系》读后感(一)
SpringIOC IOC有两种方式:一种是DI,另一种是DL,即Dependency Lookup(依赖查找).前者是当前软件实体被动接受其依赖的其他组件被IoC容器注入,而后者则是当前软件实体主动 ...
- 《SpringBoot揭秘 快速构建微服务体系》读后感(五)
应用日志和spring-boot-starter-logging 快速web应用开发与spring-boot-starter-web 1.项目结构层面的约定
- 《SpringBoot揭秘 快速构建微服务体系》读后感(三)
SpringApplication:SpringBoot程序启动的一站式解决方案 深入探索SpringApplication执行流程 因为书上的版本是1.2的,比较老,这里参考http://blog. ...
- 《SpringBoot揭秘 快速构建微服务体系》读后感(二)
最简单的springBoot应用 package com.louis.test; import org.springframework.boot.SpringApplication; import o ...
- 《SpringBoot揭秘 快速构建微服务体系》读后感(四)
再谈自动配置 基于条件的自动配置 调整自动配置的顺序
- [高清] SpringBoot揭秘快速构建微服务体系
------ 郑重声明 --------- 资源来自网络,纯粹共享交流, 如果喜欢,请您务必支持正版!! --------------------------------------------- 下 ...
- SpringBoot 快速构建微服务体系 知识点总结
可以通过http://start.spring.io/构建一个SpringBoot的脚手架项目 一.微服务 1.SpringBoot是一个可使用Java构建微服务的微框架. 2.微服务就是要倡导大家尽 ...
- SpringBoot揭秘:快速构建微服务体系
chapter 2: 饮水思源:回顾与探索Spring框架本质 IoC其实有两种方式,一种是DI(dependency Injection),一种是DL(dependency Lookup 依赖查找, ...
- 通过GeneXus如何快速构建微服务架构
概览 “微服务”是一个非常广泛的话题,在过去几年里,市面上存在着各种不同的定义. 虽然对这种架构方式没有一个非常精确的定义,但仍然有一些概念具有代表性. 微服务有着许多围绕业务能力.自动化部署.终端智 ...
随机推荐
- Win10上Python3通过pip安装时出现UnicodeDecodeError
http://blog.csdn.net/qq_33530388/article/details/68933201 解决方法: 打开 c:\program files\python36\lib\sit ...
- 远程访问(post 传参数) 以及IOUtils复制文件
package com.action; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream ...
- cmake使用第三方库
1 link_directories和target_link_libraries 1.1 link_directories 告诉linker去这些目录去找library. 1.2 target_lin ...
- adjA=(detA)A-1
A–>adjA 连续性 反函数
- PECL的安装和使用
下载并安装pear脚本 cd /usr/local/php/bin/ curl -o go-pear.php http://pear.php.net/go-pear.phar ./php go-pea ...
- 微信小程序开发:学习笔记[3]——WXSS样式
微信小程序开发:学习笔记[3]——WXSS样式 快速开始 介绍 WXSS(WeiXin Style Sheets)是一套用于小程序的样式语言,用于描述WXML的组件样式,也就是视觉上的效果. WXSS ...
- java.lang.UnsupportedClassVersionError: com/dw/Function : Unsupported major.minor version 52.0
本地环境中有jdk7和jdk8,当把jdk8改为jdk7时,出现如下错误,是jdk版本的问题,在Properties-->JAVA Compiler-中的Compiler compliance ...
- 4.2 《锋利的jQuery》jQuery中的动画
问题:queue()方法? tip0: jquery从1.9版本以上就不支持toggle()方法. // $("#panel h5.head").toggle(function() ...
- git显示颜色配置
启用默认的颜色设置可以使用如下命令 git config --global color.ui true 如果不喜欢花花绿绿的颜色,可以将其关闭: git config --global color.u ...
- ubuntn14.04 使用 nvm创建多版本node环境
1. 下载 nvm wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash 2. 然后 ...