多线程基本概念

1)线程包括哪些状态,分别是什么?

1.新建状态(new)  :线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()

2.就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行

3.运行状态(Running):线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态

4.阻塞状态(Blocked)阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
    (02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
    (03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕

5.死亡状态(dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

2)实现多线程的方式

1.继承Thread类,重写run()方法

Thread本质上也是实现了Runnable接口的一个实例,它代表了一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()方法

代码实现:

public class MyThread extends Thread {
    private int ticket = 10;

    public void run() {
        for (int i = 0; i < 20; i++) {
            if (this.ticket > 0) {
                System.out.println(this.getName() + " 卖票:ticket" + this.ticket--);
            }
        }
    }

    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        MyThread thread3 = new MyThread();
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行结果:

Thread-1 卖票:ticket10
Thread-1 卖票:ticket9
Thread-1 卖票:ticket8
Thread-1 卖票:ticket7
Thread-1 卖票:ticket6
Thread-1 卖票:ticket5
Thread-1 卖票:ticket4
Thread-1 卖票:ticket3
Thread-1 卖票:ticket2
Thread-1 卖票:ticket1
Thread-0 卖票:ticket10
Thread-0 卖票:ticket9
Thread-0 卖票:ticket8
Thread-0 卖票:ticket7
Thread-2 卖票:ticket10
Thread-0 卖票:ticket6
Thread-2 卖票:ticket9
Thread-2 卖票:ticket8
Thread-2 卖票:ticket7
Thread-2 卖票:ticket6
Thread-2 卖票:ticket5
Thread-2 卖票:ticket4
Thread-2 卖票:ticket3
Thread-2 卖票:ticket2
Thread-2 卖票:ticket1
Thread-0 卖票:ticket5
Thread-0 卖票:ticket4
Thread-0 卖票:ticket3
Thread-0 卖票:ticket2
Thread-0 卖票:ticket1

 

2.实现Runnable接口,并实现run()方法

以下是主要步骤:

1)自定义类并实现Runnable接口,实现run()方法。

2)创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象

3)调用Thread的start()方法

代码实现:

public class MyThread implements Runnable {
    private int ticket = 10;

    public void run() {
        for (int i = 0; i < 20; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName() + " 卖票:ticket" + this.ticket--);
            }
        }
    }

    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        Thread thread1=new Thread(myThread);
        Thread thread2=new Thread(myThread);
        Thread thread3=new Thread(myThread);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行结果:

Thread-0 卖票:ticket9
Thread-1 卖票:ticket10
Thread-2 卖票:ticket8
Thread-1 卖票:ticket6
Thread-0 卖票:ticket7
Thread-1 卖票:ticket4
Thread-2 卖票:ticket5
Thread-1 卖票:ticket2
Thread-0 卖票:ticket3
Thread-2 卖票:ticket1

说明:运行结果表示一共卖出了10张票,说明这三个线程共享了Runnable接口

3.实现Callable接口,重写call()方法(这种方法不常用)

Callable接口实际是属于Executor框架中的功能类...

3)run()方法和start()方法有什么区别

start()方法:作用为启动一个线程,启动后该线程处于就绪状态,而非运行状态,也就意味着这个线程可以被JVM来调度执行。

在调度过程中,JVM通过调用线程类的run()方法来完成实际的操作,当run()方法结束后,线程就会终止。

run()方法:如果直接调用线程类的run()方法,会被当做一个普通函数调用,程序中仍然只有主线程这一个线程,并不会产生新的线程

总的来说:start()方法能够异步地调用run()方法,但是直接调用run()方法却是同步的,无法达到多线程的目的

代码示例:

public class ThreadDemo extends Thread{
    @Override
    public void run() {
        System.out.println("ThreadDemo:begin");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("ThreadDemo:end");
    }
}
public class StartAndRunTest {
    /*
    test1调用start()方法
     */
    public static void test1(){
        System.out.println("test1:begin");
        Thread t1=new ThreadDemo();
        t1.start();
        System.out.println("test1:end");
    }

    /*
    test2调用run()方法
     */
    public static void test2(){
        System.out.println("test2:begin");
        Thread t1=new ThreadDemo();
        t1.run();
        System.out.println("test2:end");
    }

    public static void main(String[] args) {
        test1();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println();
        test2();
    }
}

运行结果:

从test1的运行结果来看,线程t1是在test1方法结束后才执行的,不需要等待t1,start()运行结束后(

 System.out.println("ThreadDemo:end")

)就可以执行,说明在test1中调用start()是新开启了一个线程,main线程和t1线程是异步执行的

从test2的执行结果来看,调用t1.run()是同步的调用,语句System.out.println("ThreadDemo:end")必须等t1.run()方法调用结束后

才能 执行

 4)sleep()方法与wait()方法的区别

1.原理不同。sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,它会使此线程暂停执行一段时间,而把执行机会让给

其他线程,等到计时时间一到,此线程会自动“苏醒”。

wait()方法是Object类的方法,用于线程间的通信,这个方法会使当前拥有该对象锁的进程等待,wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前的线程。

2.对锁的处理机制不同。调用sleep()方法不会释放锁,而调用wait()方法会释放它所占用的锁,从而使线程所在对象中的其他synchronized数据可被别的线程使用。

3.使用区域不同。由于wait()方法的特殊意义,因此它必须放在同步控制方法或者同步语句块中使用,而sleep()方法则可以放在任何地方使用

还有就是sleep()方法必须捕获异常,而wait()方法不需要



原文地址:https://www.cnblogs.com/wutongshu-master/p/10874090.html