java 线程详解

5月7号  周末看了一下线程方面的内容 ,边看视频边看书还附带着参考了很多人的博客,一天的收获,写下来整理一下;感觉收获还是挺多的;过段时间可能看完java  这几大块要去看一下关于spring boot  的内容顺便  也整理一下;附上我参考的 几本书;

关于java  线程,首先要了解一下线程和进程之间的关系、区别以及他们之间的概念;

首先是线程:

  • 什么是线程?

  线程是在程序执行过程中能够执行部分代码的一个执行单元,也看看做是一个轻量级的进程;线程是程序内的程序控制流只能使用程序内分配给程序的资源和环境

  • 关于线程在java语音中的五种状态
  1.    新建
  2. 就绪   :可运行状态  表示已经准备就绪但是没有抢占到cpu  资源;处于等待状态
  3. 运行   :得到cpu  资源,正在运行的状态
  4. 阻塞   :当线程运行中需要处理IO类操作,不需要用到cpu  资源的时候,便产生这种状态;
  5. 死亡   :线程出现异常或者 run()方法结束

关于进程

  • 什么是进程

  进程是指正在执行的一种程序(注意:程序是一种静态的概念,进程是一种动态的概念),可以包含多个线程,多个进程的内部数据和状态都是完全独立的

线程与进程之间的比较

  1. 线程可以看做是一个轻量级进程;一个进程中可以存在多个线程,各个线程之间共享程序(进程)的内存空间、进程资源
  2. 各个线程之间拥有独立的栈空间
  3. 线程 的创建和切换比进程的开销更小;

多线程

  •   多线程是指在单个程序中运行不同的线程执行不同的任务(在java 中指 一个程序交替执行不同的代码)
  • 目的:  最大限度的利用cpu资源,当某一线程不需要使用cpu  资源时,让正在等待cpu  资源的线程使用;
  • 一般我们所运行的java程序  main方法所运行的就是一个主线程;

接下来回归到java  ,java 中目前常用实现线程的方式

  1. 继承Thread 类重写里面的Run()方法
  2. 实现Runnable 接口并事项该接口的run() 方法
  3. 实现Callable 接口重写 call()方法 、

1.先从 Thread  直接 上代码  部分讲解都会在  代码注释中呈现出来   ,

多线程操作注意事项:

  • 必须调用它的start  方法启动线程    只有通过start 方法 实现的才是  线程   如果直接启用RUn()方法   就是一个普通类而已;
  • 正常如果多个线程同时 执行的话  ,看cpu核数,单核的话:宏观并行,微观串行;多核cpu可以做到微观并行;正常现在的电脑已经没有单核的了;
  • Thread 也是实现了Runnable  方法的 然后对其进行封装的;

下面是常用的三种线程开启使用方法代码:(这两种方法   不提供直接返回值的)

/**
 * Created by 杨一 on 2017/5/3.
 */
public class 多线程 {
    public static void main(String[] args){
        /*
         调用它的 start 方法 启动线程
         start  方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法;
         *  */
        ThreadTest1 threadTest = new ThreadTest1();
        Thread threadTest2 = new Thread(new ThreaTest2());
        threadTest.start();
        threadTest2.start();
    }

}

/*
*  创建一个线程类   使它继承一个Thread
*  */
class ThreadTest1 extends Thread {
    /*  重写run()方法*/
    @Override
    public void run() {
        super.run();

        for(int i=0;i<100;i++) {
            System.out.println("继承Thread,重写run()方法"+i);
        }
    }
}
/*
*  创建一个线程类   使它继承一个Thread
*  */
class ThreaTest2 implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<100;i++) {
            System.out.println("实现Runnable接口 ,重写run()方法"+i);
        }
    }
}

下面这种线程是se1.5引入的新特性 Callable接口(可以实现带返回值)

public class 多线程 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
      /*  *//*
         调用它的 start 方法 启动线程
         start  方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法;
         *  *//*
        ThreadTest threadTest = new ThreadTest();
        Thread thread = new Thread(threadTest);
        Thread thread1 = new Thread(threadTest);
        thread.start();
        thread1.start();*/

         /* callable  的使用*/
         CallableTest callableTest = new CallableTest();
        FutureTask<String> futureTask = new FutureTask<String>(callableTest);
        Thread thread  = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());
    }

}

/*  callable  实现带返回参数的线程  */
class CallableTest implements Callable<String> {
    @Override
    public String call() throws Exception {
        String aa = "线程中返回的值";
        return aa;
    }
}

 

关于线程停止  本身 stop()方法 是不安全的   关于原因参考:http://blog.csdn.net/jiangwei0910410003/article/details/19900007

一般停止的话  只需要让run()方法不在执行就可以让它自动销毁;代码:

/*
*  创建一个线程类   使它继承一个Thread
*  */
class ThreadTest1 extends Thread {
    private boolean flag = true;
    /*  重写run()方法*/
    @Override
    public void run() {

        super.run();
        /*  用while 循环类结束线程  */
        while (flag) {
            for (int i = 0; i < 100; i++) {
                System.out.println("继承Thread,重写run()方法" + i);
            }
        }
    }
}

接下来是关于  多线程同步的问题  :

  • 不同的线程对相同对象中的成员变量操作的时候  是你相互影响的
  • 不同的线程对对象中的局部变量不会影响;

代码:

public class 多线程 {
    public static void main(String[] args) {
        /*
         调用它的 start 方法 启动线程
         start  方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法;
         *  */

        ThreadTest threadTest = new ThreadTest();
        Thread thread = new Thread(threadTest);
        Thread thread1 = new Thread(threadTest);

        thread.start();
        thread1.start();
    }

}

class ThreadTest implements Runnable {
     int a;
    @Override
    public void run() {
        /*int a = 0;*/

        while (true){
            System.out.println("数字"+a++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(a==20){

                break;
            }

        }
    }
}

成员变量  和部分变量产生的结果;

java  synchronized   :  参考:http://blog.csdn.net/luoweifu/article/details/46613015

  • java中每个对象都有一个锁(lock)或者监视器(monitor)当访问该对象的syncronized方法时即表示对该对象上锁;
  • 对于线程来说一旦上锁之后被访问,其他线程将不能再去访问,除非上一个线程被释放或者死亡;、
  • 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;

    2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

    3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;

    4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

public class 多线程 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
      /*  *//*
         调用它的 start 方法 启动线程
         start  方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法;
         *  *//*
        ThreadTest threadTest = new ThreadTest();
        Thread thread = new Thread(threadTest);
        Thread thread1 = new Thread(threadTest);
        thread.start();
        thread1.start();*/

         /* callable  的使用*/
       /*  CallableTest callableTest = new CallableTest();
        FutureTask<String> futureTask = new FutureTask<String>(callableTest);
        Thread thread  = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());*/

        SyncTest syncTest = new SyncTest();
        Thread thread1 = new Thread(syncTest);
        thread1.start();
        Thread thread2 = new Thread(syncTest);
        thread2.start();
    }

}
/*   Syncchronized   */
class SyncTest  implements Runnable{
    @Override
    public void run() {
        synchronized (this){
            for(int i =5;i>0;i--) {
                System.out.println(Thread.currentThread().getName()+"--i" +i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

锁定方法:

锁定类的方法:

/*   Syncchronized  锁定方法  */
class SyncTest  implements Runnable{
    @Override
    public void run() {
        /* 对 类 加锁 */
        synchronized (SyncTest.class){
            for(int i =5;i>0;i--) {
                System.out.println(Thread.currentThread().getName()+"--i" +i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

关于  sleep()  和 wait()  不多讲了直接抄一篇博客的内容:http://blog.csdn.net/zidan_2011/article/details/7276468

这两者的施加者是有本质区别的.

sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定.好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧.对于运行的主动权是由我的流程来控制.

而wait(),首先,这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是

thisOBJ.wait(),这里的暂停是阻塞,还是"点火->烧水->煮饭",thisOBJ就好比一个监督我的人站在我旁边,本来该线

程应该执行1后执行2,再执行3,而在2处被那个对象喊暂停,那么我就会一直等在这里而不执行3,但正个流程并没有结束,我一直想去煮饭,但还没被允许,

直到那个对象在某个地方说"通知暂停的线程启动!",也就是thisOBJ.notify()的时候,那么我就可以煮饭了,这个被暂停的线程就会从暂停处
继续执行.

其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题

Java.lang.Thread类中,提供了sleep(),

而java.lang.Object类中提供了wait(), notify()和notifyAll()方法来操作线程

sleep()可以将一个线程睡眠,参数可以指定一个时间。

而wait()可以将一个线程挂起,直到超时或者该线程被唤醒。

wait有两种形式wait()和wait(milliseconds).

sleep和wait的区别有

1,这两个方法来自不同的类分别是Thread和Object

2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在

任何地方使用

synchronized(x){

x.notify()

//或者wait()

}

4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

时间: 2024-12-05 06:17:12

java 线程详解的相关文章

java线程详解

Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. 二.Jav

Java线程详解(三)

Java线程:新特征-有返回值的线程 在Java5之前,线程是没有返回值的,常常为了"有"返回值,破费周折,而且代码很不好写.或者干脆绕过这道坎,走别的路了. 现在Java终于有可返回值的任务(也可以叫做线程)了. 可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口. 执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了. 下面是个很简单的例子: import jav

Java线程详解(二)

Java线程:新特征-线程池 线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源. 在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建连接池的静态方法,是必须掌握的. Java通过Executor

Java线程详解(一)

程序.进程.线程的概念  程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象.  进程(process):是程序的一次执行过程,或是正在运行的一个程序.动态过程:有它自身的产生.存在和消亡的过程.     如:运行中的QQ,运行中的MP3播放器     程序是静态的,进程是动态的  线程(thread):进程可进一步细化为线程,是一个程序内部的一条执行路径.     若一个程序可同一时间执行多个线程,就是支持多线程的 Java中多线程的创建和使

java线程详解(三)

java线程间通信 首先看一段代码 class Res { String name; String sex; } class Input implements Runnable { private Res r; Input(Res r) { this.r = r; } public void run() { int x = 0; while(true){ if(x==0){ r.name = "mike"; r.sex = "male"; } else{ r.nam

Java线程详解----借鉴

Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. 二.Jav

并发编程 || Java线程详解

通用线程模型 在很多研发当中,实际应用是基于一个理论再进行优化的.所以,在了解JVM规范中的Java线程的生命周期之前,我们可以先了解通用的线程生命周期,这有助于我们后续对JVM线程生命周期的理解. 首先,通用的线程生命周期有五种,分别是:新建状态(NEW).可运行状态(RUNNABLE).运行状态(RUN).休眠状态(SLEEP).终止状态(TERMINATED).生命流程如下图所示: 新建状态(NEW).线程在此状态,仅仅是在编程语言层面创建了此线程,而在真正的操作系统中是没有创建的.所以,

java线程详解(二)

1,线程安全 先看上一节程序,我们稍微改动一下: //线程安全演示 //火车站有16张票,需要从四个窗口卖出,如果按照上面的多线程实现,程序如下 class Ticket implements Runnable { private int tick = 16;//票的张数---16 public void run(){ while(true){ if(tick>0){ //这里的sleep(100)是这次程序要表的关键,只是个模拟而已 try{ Thread.sleep(100); }catch

java线程详解(一)

1,相关概念简介 (1)进程:是一个正在执行的程序.每一个进程执行都有一个执行的顺序,该顺序就是一个执行路径,或者叫一个控制单元.用于分配空间. (2)线程:就是进程中一个独立的控制单元,线程在控制着进程的执行,一个进程中至少有一个线程. java虚拟机启动的时候会有一个进程java.exe,该进程中至少有一个线程在负责java程序的执行,这个线程运行的代码在main方法中,因此main方法是主线程.在更细节一点,java虚拟机不止一个线程,在启动main方法这个主线程时还有垃圾回收机制,其实这