• java 多线程


    要想了解多线程,必须先了解线程,要想了解线程,必须先了解进程,因为线程是依赖于进程而存在的。

    什么是进程?

      1、进程就是正在运行的程序

      2、进程是系统进行资源分配和调用的独立单位,每一个进程都有自己独立的内存空间和系统资源

    多进程的意义:

      可以在一段时间内执行多个程序,提高cpu的使用率。例如可以一边玩游戏,一边听音乐。

      注意:多个任务不是同时执行的,因为cpu在在一个时间点上只能做一件事,只不过是cpu在做着程序间的高效切换,让我们感觉像是同时执行的。

    什么是线程?

      在一个进程内可以执行多个任务,而每一个任务可以看成是一个线程

      线程:线程是程序的执行单元或叫执行路径。是程序使用cpu的基本单位

      单线程:程序只有一条执行路径

      多线程:程序有多条执行路径

    多线程的意义:

      多线程的存在不是提高程序的执行速度,而是提高了程序的使用率。

      程序的执行其实都是在抢cpu的资源,cpu的执行权。

      如果某个程序执行路径比较多,就有更高的几率抢到cpu资源。

      我们不敢保证哪个线程在哪个时刻抢到,所有线程的执行具有随机性。

    并行和并发:

      并行是逻辑上同时发生,指在一个时间段内同时运行多个程序

      并发是物理上同时发生,指在一个时间点上同时运行多个程序

    java程序的运行原理:

      由java命令启动jvm,jvm启动,就相当于启动了一个进程,接着由该进程创建一个主线程去调用main方法

      jvm虚拟机的启动时多线程的,原因是垃圾回收线程也要启动,否则会造成内存溢出。加上主线程,所有至少有两个线程启动。

    java为我们提供了Tread类来实现多线程:

    Thread类

    常用方法:

    String getName() :获取线程名

    void setName():设置线程名

    void setPriority(10); //设置线程优先级,取值为范围是 0-10,默认是5

    static Thread currentTread() :返回当前正在执行的线程对象

    static void sleep(long millis):休眠,单位为毫秒

    final void join():等待该线程终止,在线程启动后调用,在此之后的线程等此线程结束后才执行

    final void setDaemon(boolean on) :将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。 

    static final  void stop():停止线程,已过时,但是还可以使用

    void interrupt() :中断线程,把线程的状态终止,并抛出一个InterruptedException异常

    创建方式一:

    继承Thread类,步骤如下:

    1、创建子类继承Tread类

    2、重写run方法

    3、创建子类实例对象

    4、子类对象调用start()方法启动线程

    注意:run方法和start方法的区别?

      run() 仅仅是封装了线程执行的代码,和普通的方法一样

      start() 首先是启动了线程,然后由jvm去调用该线程的run方法

    创建代码如下:

    //创建Mythread类继承Thread
    public class Mythread extends Thread{
    
        //重写run方法
        @Override
        public void run() {
           for(int i=0;i<100;i++){
               System.out.println(getName()+"--"+i);
           }
        }
    }
        public static void main(String[] args) {
    
            //创建子类对象
            Mythread mythread=new Mythread();
            //开启线程
            mythread.start();
        }

    创建方式二:

    实现Runnable接口,步骤如下:

    1、自定义类实现Runnable接口

    2、子类重写run方法

    3、创建子类对象

    4、调用Thread构造方法,将子类对象当作参数传入

    和方式一比较,方式二的好处:

    a、可以避免由于java单继承性带来的局限性  b、适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码有效分类,体现了较好的面向对象设计思想。

    创建代码如下:

    //创建 RunThread 类实现Runnable接口
    public class RunThread implements Runnable {
    
        //重写run方法
        @Override
        public void run() {
    
        }
    }
        public static void main(String[] args) {
    
    
            //创建runThread接口实现类对象
            RunThread runThread=new RunThread();
            
            //调用Thread构造方法,传入runThread对象作为构造参数,创建线程
            Thread thread=new Thread(runThread);
            thread.start();
        }

     多线程安全问题产生的原因及解决办法

    1、是否是由多线程

    2、是否有共享数据

    3、是否有多条语句操作共享数据

    分析以上3点,如何3个条件都满足,就会产生安全问题。

    解决办法:synchronized

    为解决多线程安全问题,java提供了同步机制,将需要同步的代码写在同步代码块中

    用法如下所示:

        //同步能解决线程安全问题的根本原因就在于监视对象obj,该对象就如同一把锁,多个线程必须是同一把锁。此时的锁是任意对象
        private void sysFunc1(){      
            Object obj=new Object();
            synchronized (obj){
                //需要同步的代码
            }
        }
        
        //如果synchronized写在实例方法上,此时的锁是this
        private synchronized void sysFunc2(){
            //需要同步的代码
        }
        
        //如果synchronized写在静态方法上,此时锁是类的字节码文件对象。XXX.class
        private static synchronized void sysFunc3(){
            //需要同步的代码
        }

    同步的好处:可以解决线程安全问题

    同步的弊端:当线程较多,每个线程都会去判断同步锁对象,这是很耗费资源的,无形中会降低程序的运行效率

     线程间的通信:

    生产者与消费者问题:

        public static void main(String[] args) {
    
            Student s=new Student();
            Thread set=new Thread(new SetThread(s));
            Thread get=new Thread(new GetThread(s));
    
            set.start();
            get.start();
        }

    生产者线程类代码:

    /**
     * 生产者
     */
    public class SetThread implements Runnable {
    
        private Student s;
        private int x;
        public SetThread(Student s){
            this.s=s;
        }
        @Override
        public void run() {
    
            while (true){
                //SetThread是生产者,生产资源的代码如果不加锁,会出现名字和年龄对不上的情况
                synchronized (s){
                    if(x%2==0){
                        s.setName("zhangsan");
                        s.setAge(30);
                    }else {
                        s.setName("lisi");
                        s.setAge(40);
                    }
                    x++;
                }
    
            }
        }
    }

    消费者线程类代码:

    /**
     * 消费者
     */
    public class GetThread implements Runnable {
        Student s;
        public GetThread(Student s){
            this.s=s;
        }
        @Override
        public void run() {
            while (true){
                //GetThread 为消费者,消费SetThread类生产的资源,必须加上锁否则会出现名字和年龄不一致。
                synchronized (s){
                    System.out.println(s.getName()+"--"+s.getAge());
                }
    
            }
        }
    }

    生产资源Student类:

    public class Student {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
  • 相关阅读:
    成功解决vc6.0智能提示消失的BUG
    如何在vc6,vc7,vc8下编译x264
    Visual C++ 操作MS Offfice 控件
    在英文版Visual Studion 2005 professional 中使用 Windows Mobile 2003 SE中文模拟器
    x264 20060731 svn 版的编码移植
    泛型算法:Tips
    05年度EmilMatthew’s Blog文档整理
    常用软件滤波方法及其示例程序
    windows server 2003 配置
    TI C64X 视频处理应用编程重点内容提示
  • 原文地址:https://www.cnblogs.com/liujufu/p/5038884.html
Copyright © 2020-2023  润新知