Java多线程常用操作方法

线程的命名和取得

Thread类中的线程名称操作方法

  • 构造方法: public Thread(Runnable targe, String name);
  • 设置名字: public final void setName(String name);
  • 取得名字: public final String getName()

对于线程对象的获取不可能只是依靠一个this来完成的, 因为线程的状态不可控, 但是一定要执行run()方法, 所以可以获取当前线程

  • 获取当前线程: public static Thread currentThread();
eg.
class MyThreadc implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class RunnableDemo {
    public static void main(String[] args) {
        MyThreadc mt = new MyThreadc();
        new Thread(mt, "线程A").start();
        new Thread(mt).start();
        new Thread(mt, "线程B").start();
    }
}
output
线程A
线程B
Thread-0

当开发者为线程命名的时候就使用设置的名字, 如果没有设置名字, 则会自动生成一个名字, 主要依靠static属性完成的, 在Thread类里定义有如下操作:

private static int threadInitNumber;
private static synchronized int nextThreadNum() {
        return threadInitNumber++;
}
主线程

class MyThreadc implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class RunnableDemo {
    public static void main(String[] args) {
        MyThreadc mt = new MyThreadc();
        new Thread(mt, "线程A").start();
        mt.run();
    }
}
输出
线程A
main

说明在主函数中执行的是主线程, 在主线程可以创建若干个子线程, 将复杂的逻辑和耗时操作交给子线程.

进程

在执行java命令的时候就表示启动了一个JVM进程, 一台电脑上可以同时启动若干个JVM进程, 每一个JVM的进程都会有各自的线程.

线程的休眠

  • public static void sleep(long millis) throws InterruptedException
  • public static void sleep(long millis, int nanos) throws InterruptedException
 new Thread(()->{
            for (int i = 0; i < 6; i++) {
                System.out.println(Thread.currentThread().getName() + ", i = " + i);
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "线程对象").start();

多个线程执行休眠操作, 休眠顺序有先有后.

线程中断

  • 判断线程是否被中断
public boolean isInterrupted();
  • 中断线程执行
public void interrupt();

所有正在执行的线程都是可以被终端的, 中断线程的操作必须被异常处理

public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程开启");
                try {
                    Thread.sleep(10000);
                    System.out.println("线程继续");
                } catch (Exception e) {
                    System.out.println("线程卡顿");
                }
                System.out.println("线程继续");
            }
        });
        thread.start();
        Thread.sleep(1000);
        if (!thread.isInterrupted()) {
            System.out.println("线程中断");
            thread.interrupt();
        }
    }

线程强制运行

线程强制运行是指当满足于一些条件以后, 某个线程可以独占资源, 一直到该线程的程序执行结束。

public final void jion() throws InterruptedException

举例

public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {

            Thread mainThread = Thread.currentThread();
            @Override
            public void run() {
            // 不加try..catch...那么主线程和子线程交替执行
                try {
                    mainThread.join(); 
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(100);
                    } catch (Exception e) {
                }
                for (int i = 0; i < 10; i++) {
                    System.out.println("***一个线程正在执行***" + Thread.currentThread().getName() + ":" + i);
                }
            }
        }, "打酱油");
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("***一个霸道的线程正在执行***" + Thread.currentThread().getName() + ":" + i);
        }
    }

线程的礼让

线程的礼让是指先将资源让出去给别的线程执行。线程的礼让可以使用Thread的中的

public static void yield()

举例

public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {

                for (int i = 0; i < 100; i++) {
                    if (i % 3 == 0) {
                        Thread.yield();
                        System.out.println("这个线程正在礼让");
                    }
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                    }
                    System.out.println("***一个线程正在执行***" + Thread.currentThread().getName() + ":" + i);
                }
            }
        }, "打酱油");
        thread.start();
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
            }
            System.out.println("***一个霸道的线程正在执行***" + Thread.currentThread().getName() + ":" + i);
        }
    }

礼让执行的时候每次调用yield()方法,每次礼让一次当前的资源。

线程的优先级

从理论上来讲线程的优先级越高越有可能先执行(越有可能先抢占到资源)。在Thread类里面针对于优先级,有两个处理方法
获取优先级:

public final int getPriority()

设置优先级:

public final void setPriority(int newPriority)

在进行优先级定义的时候都是通过int型的数字来完成的,而对于此数字的选择在Thread类中就有明确的定义:
最高优先级

public static final int MAX_PRIORITY    // 10

中等优先级

public static final int NORM_PRIORITY  // 5

最低优先级

public static final int MIN_PRIORITY  // 1

举例

public static void main(String[] args) throws Exception {
        Runnable run = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {

                    }
                    System.out.println(Thread.currentThread().getName() + "执行:" + i);
                }
            }
        };
        Thread threadA = new Thread(run, "线程A");
        Thread threadB = new Thread(run, "线程B");
        Thread threadC = new Thread(run, "线程C");
        threadA.setPriority(Thread.MAX_PRIORITY);
        threadB.setPriority(Thread.MIN_PRIORITY);
        threadC.setPriority(Thread.MIN_PRIORITY);
        threadA.start();
        threadB.start();
        threadC.start();
    }

主线程属于中等优先级, 默认的线程的优先级属于中等优先级. 优先级高的有可能先执行, 而不是绝对先执行

线程同步

所谓的线程同步就是指多个操作在同一时间段内只能有一个线程进行, 其他进程等待此线程完成以后才可以继续执行.


线程同步
  • 同步代码块: 实现线程同步使用synchronized关键字来实现, 在同步代码块里的代码只允许一个线程执行.
synchronized(同步对象) {
    同步代码操作
}

public static void main(String[] args) throws Exception {
        Runnable run = new Runnable() {
            private int tiket = 5;
            @Override
            public void run() {
                while (true) {
                    synchronized (this) {
                        if (this.tiket > 0) {
                            try {
                                Thread.sleep(100);
                            } catch (Exception e) {

                            }
                            System.out.println(Thread.currentThread().getName() + "卖票, tiket=" + this.tiket--);
                        } else {
                            System.out.println("卖光啦~");
                            break;
                        }
                    }

                }
            }
        };
        Thread threadA = new Thread(run, "A");
        Thread threadB = new Thread(run, "B");
        Thread threadC = new Thread(run, "C");
        threadA.start();
        threadB.start();
        threadC.start();
    }
  • 同步方法: 使用synchronized修饰方法
public static void main(String[] args) throws Exception {

        Runnable run = new Runnable() {
            private int tiket = 5;

            public synchronized void sale() {
                if (this.tiket > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {

                    }
                    System.out.println(Thread.currentThread().getName() + "卖票, tiket=" + this.tiket--);
                } else {
                    System.out.println("卖光啦~");
                }
            }
            @Override
            public void run() {
                while (true) {
                    this.sale();
                }
            }
        };
        Thread threadA = new Thread(run, "A");
        Thread threadB = new Thread(run, "B");
        Thread threadC = new Thread(run, "C");
        threadA.start();
        threadB.start();
        threadC.start();
    }

在同步处理以后会造成性能的降低.

线程死锁

  • 死锁是在多线程同步的处理之中可能产生的一种问题
  • 数据同步越多, 死锁造成的就相对会严重一些

优雅的停止线程

多线程的启动是使用的Thread中的start()方法, 而如果对于多线程需要进行停止处理, Thread类提供了stop()方法, 但是从JDK1.2开始就已经被移除

  • 停止多线程: public void stop()
  • 销毁多线程: public void destroy()
  • 挂起线程: public final void suspend()
  • 恢复挂起线程执行: public final void resume()
    废除这些方法的原因: 有可能导致线程的死锁
    柔和的停止线程
public class Main {
    public static  boolean flag = true;
    public static void main(String[] args) throws Exception {

        Runnable run = new Runnable() {
            @Override
            public void run() {
                long num = 0;
                while (flag) {
                    try {
                        Thread.sleep(50);
                    } catch (Exception e) {}
                    System.out.println(Thread.currentThread().getName() + "正在运行" + num++);
                }
            }
        };
        Thread threadA = new Thread(run, "A");
        threadA.start();
        Thread.sleep(200);
        flag = false;

    }
}

flag 设置为false以后并不是立刻就停, 而是在修改完flag以后, 在进行下次flag判断的时候才会停止

后台守护线程

在多线程里面可以进行守护线程的定义, 也就是说如果现在主线程的程序或者其他线程还在运行的时候, 那么守护线程一直存在, 并且一直在后台运行

  • 设置为守护线程: public final void seDaemon(boolean on);
  • 判断是否是守护线程: public final boolean isDaemon();
    守护线程示例
public class Main {
    public static void main(String[] args) throws Exception {

        Runnable run = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 6; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {}
                    System.out.println(Thread.currentThread().getName() + "正在运行" + i);
                }
            }
        };
        Runnable run2 = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {}
                    System.out.println(Thread.currentThread().getName() + "正在运行" + i);
                }
            }
        };
        Thread threadA = new Thread(run, "A");
        Thread threadB = new Thread(run2, "守护线程");
        threadB.setDaemon(true);
        threadA.start();
        threadB.start();

    }
}

如果程序执行完毕, 那么守护线程就会消失, 在JVM里最大的守护线程就是GC.

volatile

在正常进行变量处理的时候, 往往会经历如下几个步骤

  • 获取变量原有的数据内容副本
  • 利用副本为变量进行数学计算
  • 将计算以后的变量, 保存到原始空间中
    而如果一个属性上追加了一个volatile关键字, 表示的就是不使用副本, 而是直接操作原有的内存空间, 相当于节省了拷贝副本, 重新保存的步骤.


    volatile

volatile与synchronized的区别

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

推荐阅读更多精彩内容

  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,966评论 1 18
  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,461评论 1 15
  • 一、认识多任务、多进程、单线程、多线程 要认识多线程就要从操作系统的原理说起。 以前古老的DOS操作系统(V 6....
    GT921阅读 1,015评论 0 3
  • 7月20日知识点 今天的主要内容——线程 线程线程的基本概念线程与进程的区别线程的两种创建方式(掌握)注意线程两种...
    须臾之北阅读 13,673评论 0 4
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,392评论 0 4