方法内的变量为线程安全

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多线程编程核心技术》读后感(二)的更多相关文章

  1. Springboot揭秘-快速构建微服务体系-王福强-2016年5月第一次印刷

    JavaConfig项目: spring IOC有一个非常核心的概念——Bean.由Spring容器来负责对Bean的实例化,装配和管理.XML是用来描述Bean最为流行的配置方式.Spring可以从 ...

  2. 《SpringBoot揭秘 快速构建微服务体系》读后感(一)

    SpringIOC IOC有两种方式:一种是DI,另一种是DL,即Dependency Lookup(依赖查找).前者是当前软件实体被动接受其依赖的其他组件被IoC容器注入,而后者则是当前软件实体主动 ...

  3. 《SpringBoot揭秘 快速构建微服务体系》读后感(五)

    应用日志和spring-boot-starter-logging 快速web应用开发与spring-boot-starter-web 1.项目结构层面的约定

  4. 《SpringBoot揭秘 快速构建微服务体系》读后感(三)

    SpringApplication:SpringBoot程序启动的一站式解决方案 深入探索SpringApplication执行流程 因为书上的版本是1.2的,比较老,这里参考http://blog. ...

  5. 《SpringBoot揭秘 快速构建微服务体系》读后感(二)

    最简单的springBoot应用 package com.louis.test; import org.springframework.boot.SpringApplication; import o ...

  6. 《SpringBoot揭秘 快速构建微服务体系》读后感(四)

    再谈自动配置 基于条件的自动配置 调整自动配置的顺序

  7. [高清] SpringBoot揭秘快速构建微服务体系

    ------ 郑重声明 --------- 资源来自网络,纯粹共享交流, 如果喜欢,请您务必支持正版!! --------------------------------------------- 下 ...

  8. SpringBoot 快速构建微服务体系 知识点总结

    可以通过http://start.spring.io/构建一个SpringBoot的脚手架项目 一.微服务 1.SpringBoot是一个可使用Java构建微服务的微框架. 2.微服务就是要倡导大家尽 ...

  9. SpringBoot揭秘:快速构建微服务体系

    chapter 2: 饮水思源:回顾与探索Spring框架本质 IoC其实有两种方式,一种是DI(dependency Injection),一种是DL(dependency Lookup 依赖查找, ...

  10. 通过GeneXus如何快速构建微服务架构

    概览 “微服务”是一个非常广泛的话题,在过去几年里,市面上存在着各种不同的定义. 虽然对这种架构方式没有一个非常精确的定义,但仍然有一些概念具有代表性. 微服务有着许多围绕业务能力.自动化部署.终端智 ...

随机推荐

  1. Drcom账户管理Server端解说

    https://www.github.com/xiyouMc 首先今天要讲的是针对Drcom查询账户URL的解析和抓取数据.    Drcom是大学生宿舍上网普遍使用的联网client,然而对于自己账 ...

  2. 【BZOJ4435】[Cerc2015]Juice Junctions Tarjan+hash

    [BZOJ4435][Cerc2015]Juice Junctions Description 你被雇佣升级一个旧果汁加工厂的橙汁运输系统.系统有管道和节点构成.每条管道都是双向的,且每条管道的流量都 ...

  3. 【BZOJ4238】电压 DFS树

    [BZOJ4238]电压 Description 你知道Just Odd Inventions社吗?这个公司的业务是“只不过是奇妙的发明(Just Odd Inventions)”.这里简称为JOI社 ...

  4. 解决Ubuntu(乌班图)vi/vim模式下粘贴的代码内容会多出的空格的问题

    vi/vim模式下的粘贴 因为linux系统和win系统的差异性,有时候在win环境运行的python代码会放在Linux系统上执行,这个时候就需要把win系统上IDE上的代码copy下来,在Linu ...

  5. SPFA的两个优化:SLF与LLL

    先举出个例题:洛谷P3371 [模板]单源最短路径 一眼扫去:最短路径. spfa不接受反驳... 附上代码: #include<iostream> #include<algorit ...

  6. .net编程扫盲(*)

    http://www.cnblogs.com/edisonchou/p/4787775.html

  7. Java for LeetCode 095 Unique Binary Search Trees II

    Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. For e ...

  8. LeetCode:奇偶链表【328】

    LeetCode:奇偶链表[328] 题目描述 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起.请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性. 请尝试使用原地 ...

  9. 多线程(三) iOS中的锁

    锁的类别:互斥锁,递归锁,条件锁,自旋锁等 锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等 下面说一下常用的 ...

  10. Machine Learning No.2: Linear Regression with Multiple Variables

    1. notation: n = number of features x(i) = input (features) of ith training example  = value of feat ...