再读多线程

一,概念

当代操作系统中,可以独立并发执行的基本单元。

轻量:占用系统资源少

独立:操作系统中可以陆地调度和分派的基本单位

共享:共享进程中的资源

二,实现线程

更推荐集成Runnable接口方式?

三,线程生命周期

新建:线程刚刚创建完毕

可运行:启动线程后

运行:操作系统调度中

阻塞/等待:等待资源或者时间片

消亡:退出run方法

四,常用API

静态 针对当前进程

currentThread

yield

sleep

实例方法 针对指定线程

start

setPriority/getPriority(1-10 不设置是5 不一定高优先级就能先执行)

setName/getName

setDaemon/isDaemon(守护线程是其他线程结束之后自动消亡的线程)

五,线程同步

/*
 * DESCRIPTION : 
 * USER : zhouhui
 * DATE : 2017/8/1 15:50
 */
public class SynchronizedTest {

    /**
     * method1:对方法进行锁
     */
    public synchronized void method1(){

    }

    /**
     * method2:对当前对象锁
     */
    public void method2(){
        synchronized (this){

        }
    }

    /**
     *method3:对当前对象锁
     */
    public void method3(){
        synchronized (SynchronizedTest.this){

        }
    }

    /**
     *method4:对静态方法锁
     * 静态方法属于类,所以是对类上锁
     */
    public synchronized static void method4(){

    }

    /**
     *method5:对class锁
     */
    public static void method5(){
        synchronized (SynchronizedTest.class){

        }
    }

    /**
     * method6:对成员变量锁
     */
    private Integer i = 0;
    public void method6(){
        synchronized (i){

        }
    }

}

Java语法规定,任何线程执行同步方法、同步代码块 之前,必须先获取对应的监视器。

其中method1,method2,method3都是对当前对象上锁。

method4,method5对当前类上锁

method6是对属性上锁。

对方法上锁和对代码块上锁的区别是,如果方法太大,对方法上锁的开销要大的多。

method2和method6的区别:

public class Test {

    public static void main(String[] args) {
        Data data = new Data();
        new Thread(new MyRunnable(data),"A").start();
        new Thread(new MyRunnable(data),"B").start();
    }

}

class Data{

    private Integer i = 0;

    public void show(){
        while (true){
            synchronized (i){
                if(i == 30){
                    break;
                }
                System.out.println(Thread.currentThread().getName() + " Before :" + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i ++;
                System.out.println(Thread.currentThread().getName() + " After :" + i);

            }
        }
    }
}

class MyRunnable implements Runnable{

    private Data data;

    public MyRunnable(Data data){
        this.data = data;
    }

    public void run() {
        data.show();
    }
}

synchronized (i){

synchronized (this){

会产生不同的结果。

对this上锁能够正常的在30时停止,对i上锁会打印如下:

A Before :0
A After :1
B Before :1
A Before :1
A After :2
A Before :2
B After :3
B Before :3
B After :4
A After :5
B Before :5
B After :6
B Before :6
A Before :6
A After :7
A Before :7
B After :8
B Before :8
B After :9
A After :9
B Before :9
B After :10
B Before :10
A Before :10
A After :11
A Before :12
B After :12
A After :13
B Before :13
A Before :13
A After :15
B After :15
A Before :15
A After :16
B Before :16
A Before :16
A After :17
A Before :17
B After :18
B Before :18
A After :19
A Before :19
B After :20
B Before :20
A After :21
A Before :21
B After :22
B Before :22
A After :23
A Before :23
B After :24
B Before :24
A After :25
A Before :25
B After :26
B Before :26
A After :27
A Before :27
B After :28
B Before :28
A After :29
A Before :29
B After :30
A After :31
A Before :31
A After :32
A Before :32
A After :33
A Before :33
A After :34
A Before :34
A After :35
A Before :35

但是有时候是可以成功的。

如果对i上锁,能够保证同一时间只能一个线程对i进行操作。如果一个线程能够在另外一个线程i++之前获得i那么,他是能够正常i==30停止的,但是如果在另外一个线程i++之后获得i那么,他就会直接跳过30,而继续运行。

对this上锁,意味着对整个对象上锁,只能一个线程操作代码块,保证数据的完整性。

六,线程间通信

Object对象提供了wait() notify() notifyAll()方法,被所有子类继承。

wait()获得当前对象锁的线程,释放掉当前的锁,无限期的等待,必须被其他的线程唤醒。

notify() 唤醒任意一个waiting的线程到ready状态,是否变成running状态,还需要线程调度器的调度。

notifyAll()唤醒所有的waiting的线程到ready状态。

线程间的通信其实就是停止和唤醒的过程。

以下代码实现两个线程对同一个对象的+1和-1操作,相互停止和唤醒。

/*
 * DESCRIPTION : 
 * USER : zhouhui
 * DATE : 2017/8/1 17:28
 */
public class NumberHolder {
    private int number;

    public synchronized void increase() {
        if (0 != number) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 能执行到这里说明已经被唤醒
        // 并且number为0
        number++;
        System.out.println(number);

        // 通知在等待的线程
        notify();
    }

    public synchronized void decrease() {
        if (0 == number) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        // 能执行到这里说明已经被唤醒
        // 并且number不为0
        number--;
        System.out.println(number);
        notify();
    }

}

 class IncreaseThread extends Thread {
    private NumberHolder numberHolder;

    public IncreaseThread(NumberHolder numberHolder) {
        this.numberHolder = numberHolder;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; ++i) {
            // 进行一定的延时
            try {
                Thread.sleep((long) Math.random() * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 进行增加操作
            numberHolder.increase();
        }
    }

}

 class DecreaseThread extends Thread {
    private NumberHolder numberHolder;

    public DecreaseThread(NumberHolder numberHolder) {
        this.numberHolder = numberHolder;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; ++i) {
            // 进行一定的延时
            try {
                Thread.sleep((long) Math.random() * 1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 进行减少操作
            numberHolder.decrease();
        }
    }
}

 class NumberTest {
    public static void main(String[] args) {
        NumberHolder numberHolder = new NumberHolder();

        Thread t1 = new IncreaseThread(numberHolder);
        Thread t2 = new DecreaseThread(numberHolder);

        t1.start();
        t2.start();
    }

}

打印结果:

1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
时间: 2024-12-22 00:58:56

再读多线程的相关文章

十年后2023年再读这篇文章,看看我将会怎么样?

http://blog.csdn.net/wojiushiwo987/article/details/8453881看到一篇文章不错[清华差生10年奋斗经历] ,写给将要工作的自己,十年后2023年再读这篇文章,看看我将会怎么样? 在2012年收关时刻,看到如此激励的文章,实在是我的幸运.文章讲述了所谓清华差生的奋斗史,从毕业.各种工作经历.与同事.领导关系细致入微的剖析了实战的职场及人和人差距拉开的原因等.正如文中作者指出的那样,这也是我的心灵导师俞敏洪一直教导的,”人生是跑马拉松的过程,不在

再读GFS论文

http://loopjump.com/gfs_paper_note/ 再读GFS的一些笔记.主要涉及GFS架构.Chunk大小选择的一些折中考量.元数据管理及锁.写数据流程.GFS一致性模型的理解.快照的实现原理.过期失效副本检测等几个问题.

杨绛先生送给年轻人的9句话,值得一读再读!

杨绛先生送给年轻人的9句话,值得一读再读! 1.你的问题主要在于读书不多而想得太多. 2.如要锻炼一个能做大事的人,必定要叫他吃苦受累,百不称心,才能养成坚忍的性格.一个人经过不同程度的锻炼,就获得不同程度的修养,不同程度的效益.好比香料,捣得愈碎,磨得愈细,香得愈浓烈. 3.有些人之所以不断成长,就绝对是有一种坚持下去的力量.好读书,肯下功夫,不仅读,还做笔记.人要成长,必有原因,背后的努力与积累一定数倍于普通人.所以,关键还在于自己. 4.少年贪玩,青年迷恋爱情,壮年汲汲于成名成家,暮年自安

再读J2ME游戏编程

再读J2ME游戏编程(2013.11.01) 决定再读一遍J2ME游戏编程.这本书是我2005年购自黄岛新华书店,那是第一次听说J2ME可以开发手机上的游戏,立刻就惊呆了,久久不能离去,再书店的角落捧着此书贪婪的看着,因为就这一本,可笑的怕被别人先买走,当天花了RMB79购入,这是近十天的生活费了. 重读此书,作为对作者Martin.J.Wells的崇拜之情,也因为此书是自己游戏开发的启蒙读物.虽然,从现在来讲,J2ME技术本身已经过时,但是此书中包含的游戏开发的思想,流程,步骤,术语,以及技术

如果再读一次研究生

.wiz-todo, .wiz-todo-img {width: 16px; height: 16px; cursor: default; padding: 0 10px 0 2px; vertical-align: -10%;-webkit-user-select: none;} .wiz-todo-label {margin-top: 8px; margin-bottom: 8px; line-height: 1;} .wiz-todo-label-checked { color: #666

再读大道至简第二章

懒人,第一想到的就是那种总躺在床上,吃喝拉撒睡都是要等着别人伺候的人.第一次看到标题便是不解,但是也没有特别的理解,也就这么过去了.第二次再次带着对这个的疑问和老师上课的略微讲解,便往下看第一节.这次看完第一节,才略有所悟,这里的懒人并不是真正意义上的懒,那种不会愿意做事的人,而是那种会动脑子,寻求捷径而不耽误工作效率的人. 人生在世,人的精力终归是有极限的,谁也没有比别人多几倍 的精力,纵使是爱因斯坦那样的人,他们也是牺牲了睡眠时间工作,并且以寿命为代价,毕竟因为熬夜而猝死的人现在比比皆是.为

再读《孙子兵法》

原文: 火攻第十二 孙子曰: 凡火攻有五:一曰火人,二曰火积,三曰火辎,四曰火库,五曰火队. 行火必有因,因必素具.发火有时,起火有日.时者,天之燥也. 日者,月在箕.壁.翼.轸也.凡此四宿者,风起之日也. 凡火攻,必因五火之变而应之:火发于内,则早应之于外. 火发而其兵静者,待而勿攻,极其火力,可从而从之,不可从则上. 火可发于外,无待于内,以时发之,火发上风,无攻下风,昼风久,夜风止. 凡军必知五火之变,以数守之. 故以火佐攻者明,以水佐攻者强. 水可以绝,不可以夺. 夫战胜攻取而不惰其功者

iOS开发之再探多线程编程:Grand Central Dispatch详解

之前关于iOS开发多线程的内容发布过一篇博客,其中介绍了NSThread.操作队列以及GCD,介绍的不够深入.今天就以GCD为主题来全面的总结一下GCD的使用方式.GCD的历史以及好处在此就不做过多的赘述了.本篇博客会通过一系列的实例来好好的总结一下GCD.GCD在iOS开发中还是比较重要的,使用场景也是非常多的,处理一些比较耗时的任务时基本上都会使用到GCD, 在使用是我们也要主要一些线程安全也死锁的东西. 本篇博客中对iOS中的GCD技术进行了较为全面的总结,下方模拟器的截图就是我们今天要介

再读vue2.0

玩过一段时间后在来读读vue2.0会发现受益良多 概述: vue2.0 是一套构建用户界面的渐进式框架, 使用virtual DOM  提供了响应式和组件化, 允许使用简介的模板语法来声明式的将数据渲染到DOM系统 模板语法中有过滤器功能filter---建议使用computed去完成,如果你过滤的数据不需要在其他组件中使用,那就无所谓了 提供了较为全面的指令系统(数据绑定\条件渲染与循环\事件绑定)     class和Style  社区中有这个东西完全是为了提醒你他们俩是可以绑定js对象的.