Java笔记:多线程

一、意义

使用多线程的目的是为了提高CPU资源的利用效率。在单线程应用中程序必须等待当前任务的完成才能继续执行下一项任务,CPU在等待的时间内就闲置了,多线程的使用可减少闲置时间。

二、主线程

当Java程序启动时,会立即开始运行主线程。其他所有的线程都是从主线程产生的,主线程必须是最后才结束执行的线程,因为它需要执行各种关闭动作。可以通过currentThread静态方法获取主线程的引用。

class Solution {
    public static void main(String[] args) {
        Thread t = Thread.currentThread();
        System.out.println("Current thread: " + t);//Thread[main,5,main]
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
                Thread.sleep(500);
            }
        } catch (InterruptedException exc) {
            System.out.println("Current thread interrupted");
        }
    }
}

默认情况下,主线程的名字是main,优先级是5,main也是主线程所属的线程组的名字。线程组是将线程作为一个整体来控制状态的数据结构。

三、创建线程

可通过继承Thread类或实现Runnable接口来创建线程。

实现Runnable接口创建线程时,只需要实现run方法,run方法定义线程的代码,线程随run方法结束而结束。在创建了新线程之后,只有调用start方法线程才会运行,本质上start方法执行对run方法的调用。但是Runnable接口只定义了run方法,执行run类的代码必须借助Thread实例。

扩展Thread类创建线程时, 必须重写run方法或定义Runnable接口实例。

class ThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
                Thread.sleep(500);
            }
        } catch (InterruptedException exc) {
            System.out.println(getName() + " interrupted");
        }
    }

    ThreadA(String name) {
        super(name);
        start();
    }
}

class ThreadB implements Runnable {
    private Thread t;

    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
                Thread.sleep(500);
            }
        } catch (InterruptedException exc) {
            System.out.println(t.getName() + " interrupted");
        }
    }

    ThreadB(String name) {
        t = new Thread(this, name);
        t.start();
    }
}

class Solution {
    public static void main(String[] args) {
        ThreadA tA = new ThreadA("A");
        ThreadB tB = new ThreadB("B");
    }
}

四、等待线程

当某个线程需要耗费大量时间运算,而其他线程又需要等待该线程结束后才能继续获取数据。这种情况下可直接调用该线程的join方法,程序会停留于调用join方法处直至调用该方法的线程结束才会继续执行后面的代码。

class MyThread extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
                Thread.sleep(500);
            }
        } catch (InterruptedException exc) {
            System.out.println(getName() + " interrupted");
        }
    }

    MyThread(String name) {
        super(name);
    }
}

class Solution {
    public static void main(String[] args) {
        MyThread tA = new MyThread("thread A");
        MyThread tB = new MyThread("thread B");
        MyThread tC = new MyThread("thread C");
        try {
            tA.start();
            tA.join();//停留直至tA结束
            tB.start();
            tB.join(1000);//停留1秒后无论tB是否结束都继续执行后面的代码
            tC.start();
            tC.join();//停留直至tC结束
        } catch (InterruptedException exc) {
            System.out.println("Thread interrupted");
        }
        System.out.println("Thread A is alive " + tA.isAlive());
        System.out.println("Thread B is alive " + tB.isAlive());
        System.out.println("Thread C is alive " + tC.isAlive());
    }
}

五、优先级

Java为线程指定了优先级,优先级决定了相对于其他线程会如何处理某个线程。优先级是整数,但绝对值没有意义。线程的优先级必须在MIN_PRIORITY到MAX_PRIORITY之间,在线程中是作为静态常量定义的。优先级决定何时从一个运行的线程切换到下一个,称为上下文切换。发生规则如下:

  • 线程自愿放弃控制。线程显式放弃控制权、休眠或再I/O之前阻塞,都会导致这种情况的出现。发生这种情况时,会检查其他线程,并且即将运行的线程中优先级最高的会获得CPU资源。
  • 线程被优先级更高的线程取代。没有放弃控制权的低优先级线程无论在做什么,都会被高优先级的线程取代。只要高优先级线程运行,就会取代低优先级线程,称为抢占式多任务处理。

具有相同优先级的线程竞争CPU资源时,Windows中会以循环的方式自动获得CPU资源,其他操作系统中优先级相等的线程必须主动放弃控制权其他线程才能运行。理论上优先级更高的线程会获得更多的CPU时间,具有相同优先级的线程应当得到相同的CPU时间,但不同环境的多任务方式不同,为了安全起见,具有相同优先级的线程应当时不时放弃控制权,以确保所有线程在非抢占式操作系统中有机会运行。

六、同步

多线程使程序可以进行异步行为,所以必须提供一种在需要时强制同步的方法。例如当两个线程进行通信并共享某个复杂的数据结构,当一个线程向数据结构中写入数据时,必须阻止其他线程向数据结构中写入数据,否则可能会发生冲突。

同步的关键是监视器,监视器是用作互斥锁的对象。在给定时刻只有一个线程可以拥有监视器,一旦线程进入监视器,也就是取得锁,其他所有线程就必须等待,直至该线程退出监视器,其他所有尝试进入加锁监视器的线程都会被挂起。Java中每个类都有自己隐式的监视器,每当对象的同步方法被调用时,线程就会自动进入对象的隐式监视器。

class Callme {
    synchronized void call(String msg) {//同步方法
        System.out.print("[" + msg);
        try {
            Thread.sleep(1000);
            System.out.println("]");
        } catch (InterruptedException exc) {
            System.out.println("Callme interrupted");
        }
    }
}

class Caller extends Thread {
    private String msg;
    private Callme target;

    Caller(Callme target, String msg) {
        this.target = target;
        this.msg = msg;
        start();
    }

    @Override
    public void run() {
        target.call(msg);
    }
}

class Solution {
    public static void main(String[] args) {
        Callme target = new Callme();
        Caller obA = new Caller(target, "Caller A");
        Caller obB = new Caller(target, "Caller B");
        Caller obC = new Caller(target, "Caller C");
        try {
            obA.join();
            obB.join();
            obC.join();
        } catch (InterruptedException exc) {
            System.out.println("Caller interrupted");
        }
    }
}

但是假设某个类并没有对多线程进行设计,即类中没有同步方法。由于我们并不是该类的创建者,无法访问其源代码,也就无法使用上述方法为类中的方法添加synchronized修饰符。那么可以将需要同步的部分放到synchronized代码块中。

class Caller extends Thread {
    private String msg;
    private Callme target;

    Caller(Callme target, String msg) {
        this.target = target;
        this.msg = msg;
        start();
    }

    @Override
    public void run() {
        synchronized (target) {//同步代码块
            target.call(msg);
        }
    }
}

原文地址:https://www.cnblogs.com/arseneyao/p/8447096.html

时间: 2024-10-10 02:27:37

Java笔记:多线程的相关文章

java笔记--多线程基础

多线程技术 在java中实现多线程技术有两种方式: 1.继承Thread类: 2.实现Runnable接口 这两种方法都需要重写run()方法:通常将一个新线程要运行的代码放在run()方法中(这是创建没有返回值线程的方法)由于java只支持单继承,当类已经继承有其他类时,只能选择实现Runnable接口在启动线程时需要使用Thread类的start()方法,而不是直接使用run()方法: 如: public static void function() { for (int i = 0; i

11.1-全栈Java笔记:多线程技术的基本概念

多线程是JAVA语言的重要特性,大量应用于网络编程.应用于服务器端程序的开发.以及最常见的UI界面底层原理.操作系统底层原理都大量使用了多线程. 我们可以流畅的点击软件或者游戏中的各种按钮,其实,底层就是多线程的应用.UI界面的主线程绘制界面,如果有一个耗时的操作发生则启动新的线程,完全不影响主线程的工作.当这个线程工作完毕后,再更新到主界面上. 我们可以上百人.上千人.上万人同时访问某个网站,其实,网站服务器也是基于多线程的原理.如果没有多线程,服务器处理速度会极大降低. 多线程应用于计算机的

sleep()与wait()的差别(java笔记-多线程)

1 package test; 2 3 public class test1 { 4 5 public static void main(String[] args) { 6 7 new Thread(new thread1()).start(); 8 try { 9 Thread.sleep(5000); 10 } catch (InterruptedException e) { 11 12 e.printStackTrace(); 13 } 14 new Thread(new thread2

java笔记--使用线程池优化多线程编程

使用线程池优化多线程编程 认识线程池 在Java中,所有的对象都是需要通过new操作符来创建的,如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下.这种时候就需要用到了池的技术,比如数据库连接池,线程池等. 在java1.5之后,java自带了线程池,在util包下新增了concurrent包,这个包主要作用就是介绍java线程和线程池如何使用的. 在包java.util.concurrent下的 Executors类中定义了Executor.ExecutorService.Sche

11.2-全栈Java笔记:Java中如何实现多线程

在JAVA中使用多线程非常简单,我们先学习如何创建和使用线程,然后结合案例再深入剖析线程的特性. 通过继承Thread类实现多线程 继承Thread类实现多线程的步骤: 1. 在Java中负责线程的这个功能的是java.lang.Thread 这个类 2. 可以通过创建 Thread 的实例来创建新的线程. 3.  每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体. 4.   通过调用Thead类的start()方法来启动一个线程. [示

java笔记--超级类Object多线程的应用+哲学家进餐算法内部类与多线程结合

关于Object类中的线程方法: Object类是所有Java类的 父类,在该类中定义了三个与线程操作有关的方法,使得所有的Java类在创建之后就支持多线程 这三个方法是:notify(),notifyAll(),wait(),这几个方法都是用来控制线程的运行状态的. 方法列表如下: notify() : 唤醒在此对象监视器上等待的单个线程 notifyAll() : 唤醒在此对象监视器上等待的所有线程 wait() : 在其他线程时调用此对象的notify()或者notifyAll()方法前,

java笔记--关于多线程如何查看JVM中运行的线程

查看JVM中的线程 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3890280.html "谢谢-- ThreadGroup(线程组)1.一个线程的集合,也可包含其他线程组2.线程组构成一棵树,除了初始化线程组外,每一个线程组都有一个父线程组3.允许线程访问有关自己的线程组的信息,但不能访问其父线程组或其他线程组的信息 常用方法:activeCount() 返回线程组中活动线程的估计数activeGroupCount() 返回线

java笔记--关于多线程状态的理解和应用

关于多线程的状态 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3890266.html  "谢谢-- 线程共有6种状态:1.新建线程---使用new来新建一个线程2.运行线程---调用start()方法,线程处于运行或可运行状态3.线程阻塞---线程需要获得内置锁,当该锁被其他线程使用时,此线程处于阻塞状态4.线程等待---当线程等待其他线程通知调度表可以运行时,此时线程处于等待状态5.线程计时等待---当线程调用含有时间参数的

JAVA学习笔记 -- 多线程之共享资源

在多线程程序运行过程中,可能会涉及到两个或者多个线程试图同时访问同一个资源.为了防止这种情况的发生,必须在线程使用共享资源时给资源"上锁",以阻挡其它线程的访问.而这种机制也常常被称为互斥量,本文主要介绍它的两种方式synchronized和Lock . 1.synchronized 当任务要执行被synchronized关键字保护的代码片段的时候,它会检查锁是否可用,然后获取锁,执行代码,释放锁.synchronized也有两种用法: A.synchronized方法 import

JAVA笔记:多线程的理解及应用(一)

进程与线程 进程是程序的一次动态执行过程,它经历了从代码加载.执行.执行结束的一个完整过程,这个过程也是整个进程的生命周期. 多线程是实现并发机制的一种有效手段.进程和线程一样,都是实现并发机制的基本单位. 传统的单核CPU在同一个时间段可以有多个程序在执行,但是只能有一个程序在某一时间点运行,所有的程序都要抢占CPU资源. 多核CPU下程序会并发执行. Java中多线程的实现 Java中要实现多线程可以通过以下两种方式: 1.继承Thread类 2.实现Runnable接口 1.继承Threa