Java多线程编程核心技术阅读笔记

一、java多线程技能

第一章基本上都是些Thread的简单知识科普一下,浏览了一下就过了。

二、对象及变量的并发访问

1 需要同步化的资源

只有共享的资源的读写才需要同步化。

2 类内部使用了多个synchronized

问:类内部使用了多个synchronized修饰方法,那么多个线程调用同一个类对象中不同的synchronized方法时,使用的是同一个锁吗?
答案是:使用的是同一个锁。下面的例子通过多个线程调用同一个类对象的不同synchronized方法,说明了这个问题:

import java.util.concurrent.TimeUnit;
/**
 *@author wangcanfeng
 *@note description
 *@note Created in 13:56-2018/6/27
 */
public class Test {
   public static void main(String[] args) {
       Multi m=new Multi();
        //第一个线程调用第一个测试方法
       Thread thread=new Thread(new Runnable() {
           @Override
           public void run() {
                try {
                    m.test1();
                } catch (InterruptedExceptione) {
                    e.printStackTrace();
                }
           }
       });

       //第二个线程调用第二个测试方法

       Thread thread1=new Thread(new Runnable() {
           @Override
           public void run() {
                try {
                   m.test2();
                } catch (InterruptedExceptione) {
                    e.printStackTrace();
                }
           }
       });
       //线程启动
       thread.start();
       thread1.start();
    }
}

class Multi{

   public synchronized void test1() throws InterruptedException {
       int i=0;
       for(;;){
           TimeUnit.SECONDS.sleep(1);
           i++;
           System.out.println("我是1号累加器:"+i);
       }
    }

   public synchronized void test2() throws InterruptedException {
       int i=0;
       for(;;){
           TimeUnit.SECONDS.sleep(1);
           i++;
           System.out.println("我是2号累加器:"+i);
       }
    }
}

输出结果如下,并没有出现第二个方法的输出,因为被锁住了:
我是1号累加器:1
我是1号累加器:2
我是1号累加器:3

3 synchronized继承

子类是不能继承父类的synchronized,即使父类的方法标注了synchronized,子类去调用父类的该方法,还是不具备同步特性,需要子类自己的方法前加上synchronized。这一点也很好理解,子类都已经把父类的方法继承过来了,子类就需要自己去定义这个方法了,因为这个方法已经和父类没有关系了。

4 synchronized作用

synchronized同步方法和代码块,在同一时间只有一个线程可以访问,阻塞其他线程的调用。

5 synchronized标注静态方法和非静态方法的区别

synchronized加到静态方法和非静态方法上具有本质区别,synchronized加到静态方法上是给Class类上锁,而非静态方法是给对象上锁。Class锁可以对类的所有对象实例起作用。

6 synchronized不使用String做锁对象

synchronized一般不使用String对象作为锁对象,因为String是采用的引用方式,有可能多个String对象引用的是同一个对象。

7 volatile存在线程不安全

volatile只支持变量的可见性,不支持原子性,因为变量在修改过程中会涉及到很多个操作步骤:主内存中取值到工作内存,修改值,将修改后的值刷回到主内存。volatile采用的内存屏障,只能保证它读到的数据是最新的,而不能保证它读到之后还是最新的。

8 while操作导致的死锁

public class Test {

   public static void main(String[] args) throws InterruptedException {
     Service service=new Service();
    //第一个线程用于启动while循环
     Thread1 thread1=new Thread1(service);
     thread1.start();
     Thread.sleep(1000);
     //第二个线程用于停止while循环
     Thread2 thread2=new Thread2(service);
     thread2.start();
       System.out.println("我再干嘛");
    }
}

class Service {
 private boolean isRun=true;
 public void runM(){
     int i=0;
     while (isRun==true){
          //这里如果加入一些如下代码,减缓while操作,那么可以退出while,
         //如果while没有操作,那么将出现死锁。推测可能是while太频繁,
         //没有去主内存中获取到isRun的值的更新。
//         System.out.println(i++);
//         try {
//              TimeUnit.MILLISECONDS.sleep(1);
//         } catch (InterruptedException e) {
//              e.printStackTrace();
//         }
     }
     System.out.println("ting zhi le ");
  }

 public void stop(){
     isRun=false;
    }

}

class Thread1 extends Thread{

   private Service service;
   public Thread1(Service service){
       this.service=service;
    }

   public void run(){
       service.runM();
    }
}



class Thread2 extends Thread{

   private Service service;
   public Thread2(Service service){
       this.service=service;
    }

   public void run(){
       service.stop();
    }

}

三、线程间通信

9 wait使用注意点

执行线程的wait方法必须要在同步代码块或同步方法中,即需要被synchronized修饰(或是其他的Lock)。Sleep虽然可以在没有synchronized修饰的方法和代码块中使用,但是它不会释放资源,它还是霸占了锁,让其他的资源只能进行等待。Notify也需要在锁修饰的方法或代码块中使用。

10 我的疑问

有个疑问:线程在执行wait的时候,cpu是怎么记住它的状态,使得其后续可以恢复

11

线程join的时候再调用方法interrupt会报错。

12 join与sleep的区别

join(long)和sleep(long)的主要区别在于join方法内部调用的是wait方法,而wait方法是会释放锁的,同理join也会释放锁。然后sleep不会释放锁。

13 跨线程使用ThreadLocal

即使是在不同的线程中使用同一个ThreadLocal的实例对象,它get到的值还是会返回当前线程中set的值。因为它的源码中使用Thread t = Thread.currentThread();来获取当前线程的数据。

14 InheritableThreadLocal可以继承父线程中设置的值

InheritableThreadLocal可以继承父线程中设置的值,这个父线程的概念不是说是继承关系上的父线程,而是一个父线程中的新开了子线程(新建子线程对象),子线程中可以读到父线程中的值。

四.Lock的使用

15 读锁

学习Lock的使用,在读操作频繁写操作少量的情况下可以使用ReentrantReadWriteLock。

五.定时器Timer

16 Timer取消任务注意点

Timer中的cancel方法可以用于取消任务,但不是每次都可以成功的取消,观察源码发现,它需要争取到queue的锁才可以做任务取消。

六 单例模式与多线程

17 延迟加载中的DCL双检查

public class Test {

   //volatile可以保证对象在多线程中的可见性。
   //给Test对象初始化过程中jvm有三个步骤:
   //1.给test对象分配内存
   //2.调用构造函数
   //3.将test对象的指针指向分配好的内存空间
   //但是在指令重排序的时候2和3不一定还能维持2在3前面。
   //如果1,3已经执行,2未执行,test对象虽是非空的,但却是未初始化的,这个对象是不可使用的。
   //volatile的特性可以将获取对象的操作隔离在构造函数之外,也就是2一定在3的前面
   private volatile static Test test;
   private Test() {
       //私有构造防止外部通过构造器生成实例对象
    }

   public static Test getInstance() {
        try {
           if (test != null) {
                //双重检查的第一个非空检查没有加锁,减少了锁的争用
                //随着jvm性能优化DCL,出现的原因(启动加载缓慢,同步锁执行缓慢)已经逐渐消失
           } else {
                TimeUnit.SECONDS.sleep(10);
                //class锁,对所有使用该方法的对象都有效
                synchronized (Test.class) {
                    if (test == null) {
                        test = new Test();
                    }
                }
           }
       } catch (InterruptedException ie) {
           ie.printStackTrace();
       }
       //若这个对象是没有执行过构造函数的,那么直接拿去用是很危险的
       return test;
    }
}

18 反序列化的时候保持同一个对象需要使用如下代码返回对象

protected Object readResolve() throwsObjectStreamException{
return object;
}

19 线程设置异常处理器

线程对象使用setUncaughtExceptionHandler设置异常处理的Handler。通过静态方法setDefaultUncaughtExceptionHandler设置通用异常处理方法

原创文章转载请标明出处
更多文章请查看
http://www.canfeng.xyz

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容