《Java多线程编程核心技术》读后感(五)

下面验证上面三条结论
验证第一条结论:
package Second;
public class MyObject {
}
package Second;
public class Service {
    public void testMethod1(MyObject object) {
        synchronized (object) {
            try {
                System.out.println("testMethod1 ____getLock time="
                        + System.currentTimeMillis() + " run ThreadName="
                        + Thread.currentThread().getName());
                Thread.sleep(2000);
                System.out.println("testMethod1 releaseLock time="
                        + System.currentTimeMillis() + " run ThreadName="
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    private MyObject object;
    public ThreadA(Service service, MyObject object) {
        super();
        this.service = service;
        this.object = object;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod1(object);
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    private MyObject object;
    public ThreadB(Service service, MyObject object) {
        super();
        this.service = service;
        this.object = object;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod1(object);
    }
}
package Second;
public class Run1_1 {
    public static void main(String[] args) {
        Service service = new Service();
        MyObject object = new MyObject();
        ThreadA a = new ThreadA(service, object);
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB(service, object);
        b.setName("b");
        b.start();
    }
}

同步的原因是使用了同一个“对象监视器“”。如果使用不同的“”对象监视器“”会出现什么效果呢?见下面
package Second;
public class Run1_2 {
    public static void main(String[] args) {
        Service service = new Service();
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
        ThreadA a = new ThreadA(service, object1);
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB(service, object2);
        b.setName("b");
        b.start();
    }
}
package Second;
public class Run1_2 {
    public static void main(String[] args) {
        Service service = new Service();
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
        ThreadA a = new ThreadA(service, object1);
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB(service, object2);
        b.setName("b");
        b.start();
    }
}

验证第2个结论
package Second;
public class MyObject {
    synchronized public void speedPrintString() {
        System.out.println("speedPrintString ____getLock time="
                + System.currentTimeMillis() + " run ThreadName="
                + Thread.currentThread().getName());
        System.out.println("-----------------");
        System.out.println("speedPrintString releaseLock time="
                + System.currentTimeMillis() + " run ThreadName="
                + Thread.currentThread().getName());
    }
}
package Second;
public class Service {
    public void testMethod1(MyObject object) {
        synchronized (object) {
            try {
                System.out.println("testMethod1 ____getLock time="
                        + System.currentTimeMillis() + " run ThreadName="
                        + Thread.currentThread().getName());
                Thread.sleep(5000);
                System.out.println("testMethod1 releaseLock time="
                        + System.currentTimeMillis() + " run ThreadName="
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    private MyObject object;
    public ThreadA(Service service, MyObject object) {
        super();
        this.service = service;
        this.object = object;
    }
    @Override
    public void run() {
        super.run();
        service.testMethod1(object);
    }
}
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.speedPrintString();
    }
}
package Second;
public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        MyObject object = new MyObject();
        ThreadA a = new ThreadA(service, object);
        a.setName("a");
        a.start();
        Thread.sleep(100);
        ThreadB b = new ThreadB(object);
        b.setName("b");
        b.start();
    }
}

验证第3个结论
其他代码与第二个实验相同
package Second;
public class MyObject {
    public void speedPrintString() {
        synchronized (this) {
            System.out.println("speedPrintString ____getLock time="
                    + System.currentTimeMillis() + " run ThreadName="
                    + Thread.currentThread().getName());
            System.out.println("-----------------");
            System.out.println("speedPrintString releaseLock time="
                    + System.currentTimeMillis() + " run ThreadName="
                    + Thread.currentThread().getName());
        }
    }
}

静态同步synchronized方法与synchronized(class)代码块
是对当前的*.java文件对应的class类进行持锁
package Second;
public class Service {
    synchronized public static void printA() {
        try {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "进入printA");
            Thread.sleep(3000);
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "离开printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void printB() {
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "进入printB");
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "离开printB");
    }
}
package Second;
public class ThreadA extends Thread {
    @Override
    public void run() {
        Service.printA();
    }
}
package Second;
public class ThreadB extends Thread {
    @Override
    public void run() {
        Service.printB();
    }
}
package Second;
public class Run {
    public static void main(String[] args) {
        ThreadA a = new ThreadA();
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB();
        b.setName("B");
        b.start();
    }
}

下面展示synchronized关键字加到非static静态方法上的锁
package Second;
public class Service {
    synchronized public static void printA() {
        try {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "进入printA");
            Thread.sleep(3000);
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "离开printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void printB() {
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "进入printB");
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "离开printB");
    }
    synchronized public void printC() {
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "进入printC");
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "离开printC");
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printA();
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printB();
    }
}
package Second;
public class ThreadC extends Thread {
    private Service service;
    public ThreadC(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printC();
    }
}

异步的原因是持有不同的锁,一个是对象锁,另外一个是class锁,而class锁可以对类的所有对象实例起作用,下面验证
package Second;
public class Service {
    synchronized public static void printA() {
        try {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "进入printA");
            Thread.sleep(3000);
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "离开printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void printB() {
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "进入printB");
        System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "离开printB");
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printA();
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printB();
    }
}
package Second;
public class Run {
    public static void main(String[] args) {
        Service service1 = new Service();
        Service service2 = new Service();
        ThreadA a = new ThreadA(service1);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service2);
        b.setName("B");
        b.start();
    }
}

同步synchronized(class)代码块的作用其实和synchronized static方法的作用是一样的。下面测试
package Second;
public class Service {
    public static void printA() {
        synchronized (Service.class) {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void printB() {
        synchronized (Service.class) {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "离开printB");
        }
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printA();
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.printB();
    }
}
package Second;
public class Run {
    public static void main(String[] args) {
        Service service1 = new Service();
        Service service2 = new Service();
        ThreadA a = new ThreadA(service1);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service2);
        b.setName("B");
        b.start();
    }
}

数据类型String的常量池特性

package Second;
public class Service {
    public static void print(String stringParam) {
        try {
            synchronized (stringParam) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print("AA");
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print("AA");
    }
}
package Second;
public class Run {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

出现这样的情况就是因为String的两个值都是AA,两个线程持有相同的锁,所以造成线程B不能执行。这就是String常量池所带来的问题。
因此在大多数情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他的,比如new object()实例化一个object对象,但它并不放入缓存中。
package Second;
public class Service {
    public static void print(Object object) {
        try {
            synchronized (object) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print(new Object());
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print(new Object());
    }
}
package Second;
public class Run {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

交替打印是因为持有的锁不是同一个
同步synchronized方法无限等待与解决
同步方法容易造成死循环
package Second;
public class Service {
    synchronized public void methodA() {
        Object object1 = new Object();
        System.out.println("methodA begin");
        boolean isContinueRun = true;
        while (isContinueRun) {
        }
        System.out.println("methodA end");
    }
    synchronized public void methodB() {
        Object object2 = new Object();
        System.out.println("methodB begin");
        System.out.println("methodB end");
    }
}
package Second;
public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.methodA();
    }
}
package Second;
public class ThreadB extends Thread {
    private Service service;
    public ThreadB(Service service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.methodB();
    }
}
package Second;
public class Run {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA athread = new ThreadA(service);
        athread.start();
        ThreadB bthread = new ThreadB(service);
        bthread.start();
    }
}

线程B永远得不到运行的机会,锁死了
package Second;
public class Service {
    public void methodA() {
        Object object1 = new Object();
        synchronized (object1) {
            System.out.println("methodA begin");
            boolean isContinueRun = true;
            while (isContinueRun) {
            }
            System.out.println("methodA end");
        }
    }
    public void methodB() {
        Object object2 = new Object();
        synchronized (object2) {
            System.out.println("methodB begin");
            System.out.println("methodB end");
        }
    }
}

《Java多线程编程核心技术》读后感(五)的更多相关文章
- java多线程编程核心技术——第五章总结
		
定时器Timer的使用 1.1方法schedule(TimerTask task, Date time)的测试 1.2方法schedule(TimerTask task, Date firstTime ...
 - Java多线程编程核心技术(三)多线程通信
		
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...
 - Java多线程编程核心技术(二)对象及变量的并发访问
		
本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...
 - Java多线程编程核心技术(一)Java多线程技能
		
1.进程和线程 一个程序就是一个进程,而一个程序中的多个任务则被称为线程. 进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位. 举个例子: 打开你的计算机上的任务管 ...
 - 《Java多线程编程核心技术》知识梳理
		
<Java多线程编程核心技术> @author ergwang https://www.cnblogs.com/ergwang/ 文章末尾附pdf和png下载链接 第1章 Java多线程技 ...
 - Java多线程编程核心技术---学习分享
		
继承Thread类实现多线程 public class MyThread extends Thread { @Override public void run() { super.run(); Sys ...
 - Java多线程编程核心技术---对象及变量的并发访问(二)
		
数据类型String的常量池特性 在JVM中具有String常量池缓存的功能. public class Service { public static void print(String str){ ...
 - Java多线程编程核心技术
		
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
 - 《Java多线程编程核心技术》推荐
		
写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点 ...
 - 《java多线程编程核心技术》(一)使用多线程
		
了解多线程 进程和多线程的概念和线程的优点: 提及多线程技术,不得不提及"进程"这个概念.百度百科对"进程"的解释如下: 进程(Process)是计算机中的程序 ...
 
随机推荐
- 访问一个绝对地址把一个整型数强制转换 (typecast)为一个指针是合法的
			
在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66.编译器是一个纯粹的ANSI编译器.写代码去完成这一任务. 解析:这一问题测试你是否知道为了访问一个绝对地址把一个整型数强制转换 ...
 - intellij idea 大内存优化配置  idea64.exe.vmoptions文件配置
			
-ea-server-Xms2G-Xmx4096M-Xss2m-XX:MaxMetaspaceSize=2G-XX:ReservedCodeCacheSize=1G-XX:MetaspaceSize= ...
 - 九度OJ 1034:寻找大富翁 (排序)
			
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5925 解决:2375 题目描述: 浙江桐乡乌镇共有n个人,请找出该镇上的前m个大富翁. 输入: 输入包含多组测试用例. ...
 - Makefile注意点总结
			
1 "="和":=" "="号赋值时,如果右边的值里面有未展开的变量,要等到整个Makefile的变量处理完之后,再展开,也就是说,如果该未 ...
 - iOS Dev (53) 修复UIImagePickerController偷换StatusBar颜色的问题
			
版权声明:本文为 CSDN 博主 大锐哥(ID 为 prevention)原创文章,未经博主同意不得转载. https://blog.csdn.net/prevention/article/detai ...
 - 【Linux】服务器之间的免密登录脚本
			
在实际运维的过程中,经常需要用到免密登录,下面这个脚本实现服务器之间的免密登录,如下 比如,要实现A服务器与B.C.D服务器的免密登录,只需要将B.C.D服务器的IP地址写在serverlist.tx ...
 - The Contiki build system
			
The Contiki build system http://contiki.sourceforge.net/docs/2.6/a01796.html 先看官方文档的说明,对contiki的构建系统 ...
 - 虚拟参考站(VRS)
			
来源:https://www.sohu.com/a/149415053_391994 一.高精度定位 VRS是虚拟参考站(Virtual Reference Station)的简称.这项技术是CORS ...
 - POJ 3744 Scout YYF I:概率dp
			
题目链接:http://poj.org/problem?id=3744 题意: 有n个地雷,位置为pos[i]. 在每个位置,你向前走一步的概率为p,向前走两步的概率为1-p. 你的初始位置为1. 问 ...
 - java中indexOf()
			
Java中字符串中子串的查找共有四种方法,如下:1.int indexOf(String str) :返回第一次出现的指定子字符串在此字符串中的索引. 2.int indexOf(String str ...