关于Java多线程

Java多线程

在学习多线程之前我们需要了解一些概念。

并发(Concurrent):指两个或多个事件在同一时间段内发生。(CPU每个小时间片执行一个线程,多个操作快速切换执行)。

并行(Parallel):指两个或多个事件在同一时刻发生。(两个线程互不抢占 CPU 资源,可以同时进行)

进程:指一个内存中运行的程序,每个进程都有一个独立的运行空间。

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程至少有一个线程,可以有多个线程。

线程的调度:分为分时调度(轮流,平均分配CPU时间),抢占式调度(优先级高的线程使用CPU)。
(一)创建线程类
   第一种创建线程的方式(Thread类):
Java使用Thread类来代表线程,所有的线程对象必须是Thread类或其子类的实例。每个线程的作用就是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。通过继承Thread类来创建并启动多线程的步骤如下:
1.定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
2.创建Thread子类的实例,即创建了线程对象。
3.调用线程对象的start()方法来启动该线程。
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            System.out.println("run:"+i);
        }
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
        for (int i = 0; i <20 ; i++) {
            System.out.println("main:"+i);//main主线程
        }
    }
}

*java属于抢占式调度,哪个优先级高执行哪个,同一优先级,随机选择一个执行。

上述代码多线程原理
1.JVM首先执行main方法通向CPU的路径,这个路径叫做main线程,主线程。CPU用过这个线程,这个路径可以执行main方法。
2.new MyThread()方法在main线程内开辟一条通向CPU的新路径(即新线程),用来执行run()方法。
3.程序执行结果,即随机打印。
两个线程,一个main线程,一个新线程一起抢夺CPU的执行权(执行时间)谁抢到了谁就执行相应的代码。
多线程的内存图解
start()方法会开辟新的栈空间,如果只是调用run()方法,只是在原来的空间中进行压栈操作而已。
 
关于Thread方法中的常用方法
构造方法
•public Thread():分配一个新的线程对象。
public Thread(String name):分配一个指定名字的新的线程对象。
public Thread(Runnable target):分配一个带有指定目标(任务)的新的线程对象。
public Thread(Runnable target,String name):分配一个带有指定目标的新的线程对象。
常用方法
public String getNmae():获取当前线程名称。
public void start():导致此线程开始执行;java虚拟机调用此线程的run方法。
public void run():此线程要执行的任务在此处定义代码。
public static void sleep(long mills):当前正在执行的线程以指定的毫秒数暂停。(暂时停止执行)
public static Thread currentThread():返回当前正在执行的线程的引用。(Thread.currentThread.getNname()返回当前线程名称。)
设置线程名字的两种方式
1.使用Thread中的方法setName(name)
 void setName(String name)去改变线程的名称,使之与参数name相同。
2.创建一个带参数的构造方法,参数传递线程的名称;调用父类的带参构造函方法,把线程名称传递给父类,让父类给子线程起一个名字Thread(String name)分配新的Thread 对象。
public class MyThread extends Thread{
    public MyThread(){
    }
    public MyThread(String name){
        super(name);
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread());
        System.out.println(Thread.currentThread().getName());
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyThread thr = new MyThread();
        thr.setName("哆啦A梦");//使用setName方法直接去设置线程的名字
        thr.start();
        new MyThread("蜡笔小新").start();
        System.out.println(Thread.currentThread().getName());//显示当前线程的名字
    }
}

第二种创建线程的方式(Runnable

使用Runnable接口来创建线程。方法如下:
1.定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法同样是该线程的执行体。
2.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
3.调用对象的start()方法来启动线程。
public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        RunnableImpl imp = new RunnableImpl();
        Thread t = new Thread(imp,"哆啦A梦");
        t.start();
        for (int i = 0; i <20 ; i++) {
            try {
                t.sleep(1000);//调用sleep方法,使线程暂停1秒。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}

实现Runnable接口比Thread类所具有的优势

1.适合多个相同的程序代码去共享一个资源。

2.避免了单继承的局限性,可以去继承其他类,而不单单是Thread类

3.可扩展性高,降低了程序的耦合性(解耦

解耦:就是创建Runnable接口实现类并完成调用这一过程,把设置线程任务开启新线程实现了分离

实现类中,重写了Run方法:用来设置线程任务。

创建Thread类对象。调用start方法只需传递不同的实现类(run方法任务不同)的类的对象。

第三种创建线程的方式(匿名类)

匿名内部类的作用:简化代码

把子类继承父类,重写父类的方法,创建子类对象合成一步写完。

把实现类实现类接口,重写接口的方法,创建实现类对象合成一步完成。

格式:

  new 父类/接口(){

      重复父类/接口中的方法

}

public class Demo {
    public static void main(String[] args) {
        new Thread() {
            //重写run方法
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        }.start();
    }
    
}

 

 //接口匿名类,第一种方法
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + "黑马");
                }
            }
        };
        new Thread(r).start();
        //接口匿名类,第二种,更简便
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + "你好");
                }
            }
        }).start();

关于线程安全,有时间在更新吧~

 
 
 
 
 
 
 
 
 
 

 

posted @ 2020-02-28 00:35  SandCarving  阅读(198)  评论(0)    收藏  举报