手记

Java多线程---线程的创建和使用

Java多线程---线程的创建和使用

主要内容
程序、进程、线程的概念
Java中多线程的创建和使用
1、继承Thread类与Thread类的主要方法
2、实现Runable接口
3、线程的调度与设置优先级

一、程序、进程、线程的概念
1、程序(program):可以理解为一段静态的代码,静态对象。是为了完成特定任务、用某种语言编写的一组指令的集合。
2、进程(process):它是内存中的一段独立的空间,可以负责当前应用程序的运行。当前这个进程负责调度当前程序中的所有运行细节。
进程是一个动态过程,有它自己的产生、存在和消亡的过程。
3、线程(thread):它是位于进程中,负责当前进程中的某个具备独立运行资格的空间。
区别:进程是负责整个程序的运行,而线程是程序中具体的某个独立功能的运行。一个进程中至少应该有一个线程。
4、多线程
在一个进程中,同时开启多个线程,让多个线程同时去完成某些任务(功能)。
(比如后台服务系统,就可以用多个线程同时响应多个客户的请求)
多线程的目的:提高程序的运行效率。
多线程运行原理:
cpu在线程中做时间片的切换。其实真正电脑中的程序的运行不是同时在运行的。
CPU负责程序的运行,而CPU在运行程序的过程中某个时刻点上,它其实只能运行一个程序。而不是多个程序。
而CPU它可以在多个程序之间进行高速的切换。而切换频率和速度太快,导致人的肉眼看不到。
每个程序就是进程, 而每个进程中会有多个线程,而CPU是在这些线程之间进行切换。
了解了CPU对一个任务的执行过程,我们就必须知道,多线程可以提高程序的运行效率,但不能无限制的开线程。
二、Java中多线程的创建和使用
1、继承Thread类

(1)实例:

package com.TestThread;
/*
 * 创建一个子线程,完成1-100之间自然数的输出,同样,主线程也执行这个操作
 * 创建多线程的第一种方式:继承java.lang.Thread类
 */
//1、创建一个继承于Thread的子类
class SubThread extends Thread{
    //2、重写Thread类的run()方法,方法内实现此子线程要完成的功能
    public void run(){
        for(int i=1;i<=100;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class TestThread {
   public static void main(String[] args) {
       //3、创建一个子类的对象
       SubThread st1=new SubThread();
       SubThread st2=new SubThread();
       //4、调用线程的start()方法:启动此线程,调用相应的run()方法
       //一个线程只能够执行一次start()方法
       //不能通过Thread实现类对象的run()去启动一个线程
       st1.start();
       //st1.start()
       //st1.run()
       st2.start();
       for(int i=1;i<=100;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
}
}

(2)Thread的常用方法
实例:

package com.TestThread;
/*
 * Thread的常用方法
 * 1.start():启动线程并执行相应的run()方法
 * 2.run():子线程要执行的代码放入run()方法
 * 3.currentThread():静态的,调取当前的线程
 * 4.getName():获取此线程的名字
 * 5.setName():设置此线程 的名字
 * 6.yield():调用此方法的线程释放当前CPU的执行权
 * 7.join():在A线程中调用B线程的join()方法,表示当执行到此方法,A线程停止执行,直至B线程执行完成,A线程再接着join()之后的代码执行
 * 8.isAlive():判断当前线程是否还存活
 * 9.sleep(long L):显式地让当前线程睡眠L毫秒
 * 10.线程通信:wait()  notify()    notifyAll()
 * 设置线程的优先级:时间片,抢占式
 * getPriority():返回线程优先值
 * setPriority(int new Priority):改变线程的优先级
 */
class SubThread1 extends Thread{
    public void run(){
        for(int i=1;i<=100;i++){
            /*try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }*/
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class TestThread1 {
    public static void main(String[] args) {
           SubThread1 st1=new SubThread1();
           SubThread1 st2=new SubThread1();
           st1.setName("子线程1");
           st1.start();
           st2.setName("子线程2");
           st2.start();
           Thread.currentThread().setName("=========主线程");
           for(int i=1;i<=100;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                /*if(i%10==0){
                   Thread.currentThread().yield();  
                }*/
                if(i == 20){
                    try {
                        st1.join();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                }
           System.out.println(st1.isAlive());

            }
}

(3)设置线程的优先级:时间片,抢占式
getPriority():返回线程优先值
setPriority(int newPriority):改变线程的优先级
MAX_PRIORITY(10) MIN_PRIORITY(1) NORM_PRIORITY(5)
(4)简单练习
模拟火车站售票窗口,开启三个窗口售票,总票数为100
(此程序存在线程安全问题,打印车票时可能出现重复车票以及错票,这只是一个简单的实现,没考虑线程安全问题)

 package com.TestThread;
//模拟火车站售票窗口,开启三个窗口售票,总票数为100
//方式一:继承Thread类
class Window extends Thread{
    static int ticket=100;
    public void run(){
        while(true){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"售出的票号为:"+ticket--);
            }else{
                break;
            }
        }
    }
}
public class TestWindow {

  public static void main(String[] args) {
    Window w1=new Window();
    Window w2=new Window();
    Window w3=new Window();

    w1.setName("窗口1");
    w2.setName("窗口2");
    w3.setName("窗口3");

    w1.start();
    w2.start();
    w3.start();
}
}

2、实现Runable接口
(1)实例:

package com.TestThread;
//方式二:实现Runnable接口
//1、创建一个实现了Runnable接口的类
class PrintNum1 implements Runnable{
      //2、实现接口的抽象方法
    public void run() {
       //子类执行的代码
    for(int i=1;i<=100;i++){
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }

    }
}
public class TestRunnable {
    public static void main(String[] args) {
        //3、创建一个Runnable接口实现类的对象
        PrintNum1 p=new PrintNum1();
        //4、将此对象作为形参传递给Thread类的构造器中,创建Thread类的对象,此对象即为一个线程
        Thread t1=new Thread(p);
        //5、调用start()方法,启动线程并执行run()方法
        t1.start();//启动线程,执行Thread对象生成时构造器形参的对象的run()方法

        //再创建一个线程
        Thread t2=new Thread(p);
        t2.start();
    }

}

(2)简单练习
模拟火车站售票窗口,开启三个窗口售票,总票数为100
(此程序存在线程安全问题,打印车票时可能出现重复车票以及错票,这只是一个简单的实现,没考虑线程安全问题)

     package com.TestThread;
//使用实现Runnable接口方式售票

class Window1 implements Runnable{
   int ticket=100;
    public void run() {
        while(true){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"售出的票号为:"+ticket--);
            }else{
                break;
            }
        }

    }

}
public class TestWindow2 {

    public static void main(String[] args) {
        Window1 w=new Window1();
        Thread t1=new Thread(w);
        Thread t2=new Thread(w);
        Thread t3=new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

3、两种方式的对比
(1)联系:Thread类是实现Runnable接口的。
(2)实现Runnable接口的方式优于继承Thread类的方式
理由:a.避免了Java单继承的局限性
b.如果多个线程要操作同一份资源(或数据),更适合使用实现的方式。

1人推荐
随时随地看视频
慕课网APP