首页 > 编程语言 > 详细

十四、线程

时间:2020-10-08 18:20:49      阅读:23      评论:0      收藏:0      [点我收藏+]

1.什么是进程?什么是线程?

  进程是一个应用程序(一个进程一个软件)

  线程是一个进程中的执行场景/执行单元

  一个进程可以启动多个线程

2.对于java来说,启动JVM,JVM在启动一个主线程调用main方法,同时再启动一个垃圾回收器线程负责看护,回收垃圾。

3.进程与线程的关系?

进程与进程之间内存独立不共享。

线程与线程之间在java语言中:

  堆内存和方法去内存共享。

  栈内存独立,一个线程一个栈。

4.多线程机制可以提高程序处理效率。

5.使用对线程机制之后,main方法结束,程序可能不会结束。main方法结束,只是主栈空了,其他栈(线程)可能还在压栈弹栈。

6.JVM虚拟机:

  方法区、堆内存只有一个。多线程共享 。

  一个栈一个线程。支栈:分支线程。

7.什么是多线程并发?

  t1线程执行t1的,t2线程执行t2的。

  t1不会影响t2,t2不会影响t1。这才叫多线程并发。

8.对于一个单核的CPU来说,真的可以做到多线程并发吗?

  对于多核的CPU电脑,真正的多线程并发是没有问题的。

单核的CPU表示只有一个大脑:

  不能够做到真正的多线程并发,但是可以给人一种”多线程并发“的感觉。对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于CPU运行速度处理极快,多个线程之间频繁切换执行,给人的感觉就是同时在做。

9.实现线程的方式:

java支持多线程机制,并且java已经将多线程实现了,我们只需要继承就行。

第一种:编写一个类,直接继承java.lang.Thread,重写run方法。

  怎么创建线程对象? new就行了

  怎么启动线程? 调用线程对象的start()方法。

技术分享图片
public class Test{

    public static void main(String[] args) {
        //主线程在主栈中
        
        //创建分支线程对象
        MyThread th = new MyThread();
        
        //启动线程
        th.start();
        //start()方法的作用:启动一个分支线程,在JVM中开辟一个新的栈空间,
        //这段代码任务完成之后,瞬间就结束了。
        
        //这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开出来,
        //start()方法就结束了。线程就启动成功了。
        //启动成功的线程会自动调用run()方法并且run()方法在分支线的栈底部(压栈)。
        //run方法在分支线程的底部,main方法在主栈的栈底部,run和main是平级的。
            
        //直接调用run方法,与调用start的方法有啥区别?
        //th.run();//不会启动线程,不会分配新的分支栈。(等于在同一个栈中,单线程)
        
        //这里的代码还是运行在主线程中
        for(int i = 0; i < 100;i++) {
            System.out.println("main");
        }
    }

}
View Code

以上代码输出结果有这样的特点:有先有后。有多有少。Why?

某个线程抢到执行权。

第二种实现线程方式:编写一个类实现java.lang.Runnable接口

推荐接口:面向接口编程。一个类实现了接口,它还可以去继承其它的类,更灵活。

技术分享图片
class MyRunable implements Runnable{

    @Override
    public void run() {
        for(int i = 0; i < 100;i++) {
            System.out.println("MyRunabale");
        }
    }
    
}
public class Test{

    public static void main(String[] args) {
        //创建一个可运行的对象
        MyRunable r = new MyRunable();
        //将可运行的对象封装成一个线程对象
        Thread t = new Thread(r);
        
        //合并代码
        //Thread tt = new Thread(new MyRunable());
        //启动线程
        t.start();
        for(int i = 0; i < 100;i++) {
            System.out.println("main");
        }
    }

}
View Code

第三种采用匿名内部类的方法去实现:

技术分享图片
public class Test{

    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            
            @Override
            public void run() {
                for(int i = 0; i < 100;i++) {
                    System.out.println("Runabale");
                }
            }
        });
        
        //启动线程
        t.start();
        
        for(int i = 0; i < 100;i++) {
            System.out.println("mian");
        }
    }

}
View Code

10.线程生命周期:

  新建状态、就绪状态、运行状态、运行状态、阻塞状态、死亡状态

11、关于线程的一些操作:

11.1、怎么获取线程对象?

  public static native Thread currentThread()

Thread t = Thread.currentThread();//返回t就是当前线程。

11.2、线程对象的名字:线程对象 .getName()

11.3、修改线程对象名字:线程对象 .setName("")

11.4、当线程没有设置名字:Thread-0、Thread-1

技术分享图片
public class Test{

    public static void main(String[] args) {
        
        MyRun h = new MyRun();
        h.doSome();
        
        System.out.println();
        
        //这个代码出现在main中,所以线程就是主线程。
        Thread tt = Thread.currentThread();
        System.out.println(tt.getName());//main
        
        
        MyRun t = new MyRun();
        //t.setName("t1");
        String tName = t.getName();    //默认Thread-0
        System.out.println(tName);
        
        MyRun t2 = new MyRun();
        String tName2 = t2.getName();    //Thread-1
        System.out.println(tName2);
        
        System.out.println();
        
        t.start();
        t2.start();
    }

}
View Code

11.5、关于线程sleep()方法:

  public static native void sleep(long millis) throws InterruptedException

  • 静态方法
  • .参数是毫秒
  • 作用:让【当前线程】进入休眠状态,放弃CPU时间片,让给其他先程使用。
  • 实现:间隔特定时间,去执行一段特定的代码.
技术分享图片
public class Test{

    public static void main(String[] args) {
        try {
            Thread.sleep(1000*5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("HelloWorld");
        
        for(int i = 0;i<10;i++){
            System.out.println(Thread.currentThread().getName() + i);
            
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
View Code

11.6、终止线程的睡眠(不是终断线程的执行)

  中断睡眠的方式依靠了java的异常处理机制java.lang.InterruptedException: sleep interrupted

技术分享图片
class MyRun1 implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+ "--> begin");
        try {
            //子类重写父类不能抛出比父类更多、更宽的异常
            Thread.sleep(1000*60*60);
        } catch (InterruptedException e) {
            //打印异常信息
            e.printStackTrace();
        }
        
        System.out.println(Thread.currentThread().getName()+ "--> end");
    }
        
}

public class Test{

    public static void main(String[] args) {
        Thread t = new Thread(new MyRun1());
        t.setName("t");
        t.start();
        
        //希望在5秒后,t线程醒来
        try {
            Thread.sleep(1000*5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        //终断t线程的睡眠
        t.interrupt();
        
        
    }

}
View Code

12.关于多线程并发环境下,数据的安全问题

12.1、什么时候数据在多线程并发的环境下会存在安全问题呢?

  • 多线程并发
  • 有共享数据
  • 共享数据有修改的行为

满足以上三个条件之后,就会存在线程安全问题。

12.2、怎么解决线程安全问题?

  线程同步机制:线程排队执行。(不能并发)

  会牺牲一部分效率。(安全第一)

12.3、synchronized的三种方法:

第一种:同步代码块
synchronized(线程共享对象){
  同步代码块;
}

第二种:在实例方法上使用synchronized
  表示共享对象一定是this
  并且同步代码块是整个方法体。

第三种:在静态方法上使用synchronized
  表示找类锁。
  类锁永远只有1把。

JavaSE更新基本结束,后续或许会补充,或许不会。

上一篇:十三、IO流

下一篇:数据结构:持续更新中

十四、线程

原文:https://www.cnblogs.com/arick/p/13779577.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!