Java线程小记

线程是程序内部不同的执行分支,实现多线程主要有两种方式:继承自Thread类或实现Runnable接口,其实Thread类也是实现了Runnable接口,基于Java的单继承机制,我们建议使用实现Runnable的方式来实现线程类,Runnable接口里面只有一个run方法,线程类必须实现这个方法,多线程的业务逻辑就是写在run方法里面实现的。

线程状态的转换:

Thread t = new Thread(runnable);

这样就创建了一个线程,注意runnable是实现了Runnable接口的线程类

t.start();

线程进入就绪状态,何时被调用取决于CPU的“心情”(线程的优先级,CPU的繁忙度等等),CPU调度该线程使线程成为运行状态,执行线程类的run方法。线程在运行状态的时候有可能进入阻塞状态,例如代码中调用了Thread.sleep()/wait()或程序抛出了InterruptedException等等,当线程不满足某些条件的时候,线程会自动退出,强烈不建议使用已经废弃的stop方法来强杀线程,这样可能会引起很多问题,例如有些资源可能再也不会被适当地关闭了。

isAlive(): 检查该线程是否还活着,一个线程如果已经启动还未终止的话,那就是活着的状态。

public class IsAlive {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread myThread = new Thread(myRunnable);
        System.out.println("1. myThread isAlive ? " + myThread.isAlive());
        myThread.start();
        System.out.println("2. myThread isAlive ? " + myThread.isAlive());
        Thread.sleep(3000);
        System.out.println("3. myThread isAlive ? " + myThread.isAlive());
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("MyRunnable.run i = " + i);
        }
    }
}

setPriority和getPriority方法的作用分别是设置线程优先级和获取线程优先级,线程是有优先级的,级别分别是从1到10,1为最低级别,线程创建后默认的优先级为5,Thread类定义了3个int常量来表示线程的最低,最高和默认级别:

    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;
public class Priority {

    public static void main(String[] args) {
        MyRunnable1 myRunnable = new MyRunnable1();
        Thread myThread = new Thread(myRunnable);
        System.out.println("默认级别: " + myThread.getPriority());
        myThread.setPriority(Thread.NORM_PRIORITY + 3);
        System.out.println("新级别: " + myThread.getPriority());
    }

}

class MyRunnable1 implements Runnable {

    @Override
    public void run() {}

}

线程的优先级别越高,则CPU为其分配的时间片就越多。

Thread.sleep(): 让当前线程睡眠指定毫秒数

使用Thread.sleep(1000)来做一个类似计时器的功能

public class Sleep {
    public static void main(String[] args) {
        MyRunnable3 myRunnable = new MyRunnable3();
        Thread myThread = new Thread(myRunnable);
        myThread.start();
    }
}

class MyRunnable3 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(new Date());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

join(): 将线程加入到当前主线程来执行,等待加入线程的结束,就相当于方法调用。

如果我不使用join方法,你会看到主线程和分支线程是并发运行的:

public class Join {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable4 myRunnable = new MyRunnable4();
        Thread myThread = new Thread(myRunnable);
        myThread.start();
//        myThread.join();
        for (int i = 0; i < 3; i++) {
            System.out.println("我也要跑");
            Thread.sleep(500);
        }
    }
}

class MyRunnable4 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("跟着我跑");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

如果现在我反注释掉myThread.join()那一行,你会发现程序会先执行分支线程再执行主线程中的打印语句:

这个效果跟如下代码产生的效果是一样的,也就是普通的方法调用:

public class Join {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable4 myRunnable = new MyRunnable4();
        myRunnable.run();
        for (int i = 0; i < 3; i++) {
            System.out.println("我也要跑");
            Thread.sleep(500);
        }
    }
}

class MyRunnable4 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("跟着我跑");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

yield(): 让线程“高风亮节”让出CPU资源给其他线程执行。

死锁问题的产生原理:

假设我们有两个线程Thread1和Thread2,有两个synchronized的对象ObjA和ObjB, Thread1的执行需要先锁定ObjA再锁定ObjB来执行操作,然后才能完成任务并释放锁,Thread2则相反,它需要先锁定ObjB再锁定ObjA才能完成任务,当Thread1执行的时候发现ObjB被Thread2锁住了,所以只能等待,而Thread2视图去锁定ObjA的时候发现该对象被Thread1锁住了,所以Thread2也只能等待,于是两个对象都在等待对方释放锁,这就造成了死锁,死锁的解决方案之一是实现粗粒度的锁,不要同时在多个对象上加锁。

synchronized: 来看看一道经典的面试题

 1 public class ThreadInterview implements Runnable {
 2
 3     private int i = 100;
 4
 5     public synchronized void foo1() throws InterruptedException {
 6         i = 1000;
 7         Thread.sleep(3000);
 8         System.out.println("foo1 i = " + i);
 9     }
10
11     public void foo2() {
12         System.out.println("foo2 i = " + i);
13     }
14
15     public static void main(String[] args) throws InterruptedException {
16         ThreadInterview ti = new ThreadInterview();
17         Thread t = new Thread(ti);
18         t.start();
19         Thread.sleep(1000);
20         ti.foo2();
21     }
22
23     @Override
24     public void run() {
25         try {
26             foo1();
27         } catch (InterruptedException e) {
28             e.printStackTrace();
29         }
30     }
31 }

问20行i的值是多少?

答案是1000,为什么不是100,该题的考点在哪里?foo1是一个同步的方法,当线程t执行这个方法的时候会将ti对象锁定,但是foo2不是同步方法,main线程还是可以通过foo2访问i这个值得,由于执行顺序先后问题,i在foo1被执行的时候就改为1000了,当然foo2中的i也是1000了。考点就是,同步方法会锁定对象当时其它线程依然可以在同时访问其非同步方法。

Thread.sleep()跟Object.wait()的区别?

当线程sleep的时候,线程会在指定毫秒数之后醒过来,线程依然持有锁;线程wait的时候,线程不会主动醒过来除非有调用该线程的notify方法,wait的时候,锁不再归该线程所有。

notify方法:叫醒当前正在wait的线程。

时间: 2024-08-10 09:57:52

Java线程小记的相关文章

java中断小记(二)

在上一篇博文中,介绍了成员方法interrupt()的用法,这篇接上上篇继续介绍剩下的两个与中断有关的方法. 2.成员方法new Thread().isInterrupted() 通常使用Thread.currentThread().isInterrupted()方法判断某个线程是否已被发送过中断请求(某一线程被发送过中断请求后并一定会中断),因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false.程序示例如下: package com.szw.test;

java 线程详解

5月7号  周末看了一下线程方面的内容 ,边看视频边看书还附带着参考了很多人的博客,一天的收获,写下来整理一下:感觉收获还是挺多的:过段时间可能看完java  这几大块要去看一下关于spring boot  的内容顺便  也整理一下:附上我参考的 几本书: 关于java  线程,首先要了解一下线程和进程之间的关系.区别以及他们之间的概念: 首先是线程: 什么是线程? 线程是在程序执行过程中能够执行部分代码的一个执行单元,也看看做是一个轻量级的进程:线程是程序内的程序控制流只能使用程序内分配给程序

Java线程工作内存与主内存变量交换过程及volatile关键字理解

Java线程工作内存与主内存变量交换过程及volatile关键字理解 1. Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行.此处的所谓内存模型要区别于通常所说的虚拟机堆模型: 2. 线程独有的工作内存和进程内存(主内存)之间通过8中原子操作来实现,如下图所示: 原子操作的规则(部分): 1) read,load必须连续执行,但是不保证原子性. 2) store,write必须连续执行,但是不保证原子性. 3) 不能丢失变量最后一次ass

java线程

Java线程详解 1.操作系统中的线程和进程讲解: 现在的操作系统大都是多任务操作系统,多线程是多任务的一种. 进程是指操作系统中运行的一个程序,每个进程都有自己的一块内存空间,一个进程中可以启动多个线程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. Java线程的两种具体实现方法: 第一种继承:具体代码实现如下: Public (

Java 线程第三版 第四章 Thread Notification 读书笔记

一.等待与通知 public final void wait() throws InterruptedException 等待条件的发生. public final void wait(long timeout) throws InterruptedException 等待条件的发生.如果通知没有在timeout指定的时间内发生,它还是会返回. public final void wait(long timeout, int nanos) throws InterruptedException

Java线程使用大全

1.线程实现 1.Thread类 构造方法: 案例代码: public class Ex10_1_CaseThread extends Thread {// 创建一个类继承(extend)Thread类 String studentName; public Ex10_1_CaseThread(String studentName) {// 定义类的构造函数,传递参数 System.out.println(studentName + "申请访问服务器"); this.studentNam

java线程五种状态

java线程五种状态: 创建 -> 就绪 -> 运行 -> 销毁 创建 -> 就绪 -> 运行 -> 等待(缺少资源) -> 销毁 下图:各种状态转换

java线程详细介绍

目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1

java 线程通信

java 线程通信使用wait notify 配合synchronized 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态.当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁. 如下代码: public class ThreadTest { //声明一个线程可视化的list集合 public static List<String> lis