线程的创建


一:概念

程序:为完成特定的任务,用某种语言编写的一组指令的集合,即一段静态的代码
进程:正在运行的一个程序
线程:一个程序内部的一条执行路径

进程可以细化为多个线程
每个线程都拥有自己独立的:栈和程序计数器
多个线程共享同一个进程的结构:方法区和堆

一个进程中的多个线程共享一份方法区和堆
每个线程都有独立的程序计数器和虚拟机栈
并行:多个cpu同时执行多个任务
并发:一个CPU同时执行多个任务

二:多线程的创建

方法一:使用Thread
①:创建类来继承Thread
②:重写Thread类中的run()方法—>此线程执行的方法放在run()方法中
③:创建子类对象
④:子类调用start()方法,start()作用:调用此线程;执行此线程的run()方法

方法二:实现Runnable接口

  • 1.创建实现了Runnable接口的类
  • 2.实现Runnable中的唯一一个抽象方法:run()
  • 3.创建实现类的对象
  • 4.将实现类的的对象放到Thread类的构造器中,创建Thread类对象
  • 5.通过Thread类的对象调用strat()方法

方法三:Lock锁 —JDK5.0新增

  • 1.面试题:synchronized与lock的异同?
  • 相同:都是去解决线程安全问题
  • 不同点:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
  • Lock需要手动的启动同步(lock()),同时手动结束同步(unlock())
    *2.优先使用顺序:
  • lock ->同步代码块 ->同步方法
  • 面试题:如何解决线程的安全问题?有几种方式?
  • 三种:lock和两种synchronized

方法三:Lock锁举例

//方法三::Lock锁
class Window implements Runnable{
    private int ticket = 100;
    //1.实例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock(false);//默认值为false,true的意思为公平,谁先到谁先有使用权
    @Override
    public void run() {

        while(true) {
            //2.调用lock()
            lock.lock();
                try {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (ticket > 0) {
                        System.out.println(Thread.currentThread().getName() + "\t" + ticket);
                        ticket--;
                    }
                }finally {
                    //3.调用解锁方法:unlock()
                    lock.unlock();
                }


        }

    }
}

public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();

        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();
    }
}

三:测试Thread中的常用方法

1.start():启用当前线程;调用当前线程的run()方法
2.run():通常需要重写Thread中的run()方法,将创建的线程要执行的
操作申明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名称
5.setName():设置当前线程的名称
6.yield():释放当前CPU的执行权
7.join():在线程A中调用线程B的join(),此时线程A就进入阻塞状态,直到线程B都执行完
线程A才结束阻塞状态。
8.stop():已过时,当执行此方法时,强制结束当前线程。
9.sleep(long millitime):让当前线程睡眠指定的millitime毫秒,在这个睡眠时间里线程是阻塞状态
10:isAlive():判断当前线程是否存活

四:线程的优先级

一:
MAX_PRIORITY: 10
MIN_PRIORITY: 1
NORM_PRIORITY: 5 ----->默认优先级
二:如何获取和设置当前的优先级
getPriority():获取
setPriority():设置

高优先级的线程抢占低优先级的CPU执行权,只是从概率上讲,高优先级的线程
高概率的情况下被执行,并不意味着高优先级线程全执行完执行低优先级

*/

五:比较线程的两种创建方式:

  • 开发中:优先选择 Runnable接口的方式

  • 原因:
    1.实现的方式没有类的单继承的局限性
    2.实现的方式更适合来处理多个线程有共享数据的情况

  • 联系:public class Thread implements Runnable

  • 相同点:两种方式都重写run(),将线程的执行写在run()中,目前两种方式,要想启动线程,都是调用的Thread类中的start()

线程通信:wait(),notify(),notifyAll():此三个方法定义在Object类中。

补充:线程的分类:一种是守护线程,一种是用户线程。

1.它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
2.守护线程是用来服务用户线程的,通过在start()方法前调用。thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
3.Java垃圾回收就是一个典型的守护线程。
4. 若JVM中都是守护线程,当前JVM将退出。

六:线程的生命周期

在这里插入图片描述

七:线程同步

  • 例子:创建三个窗口卖票,总票数为100张
  • 存在线程安全问题,待解决
  • 1.问题:卖票过程中,出现了重票、错票–>出现了线程的安全问题
  • 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票
  • 3.如何解决:当一个线程在操作ticket的时候,其他线程不能参与进来,直到线程a操作完ticket时,其他线程才可以操作ticket,这种即使线程a出现了阻塞,也不能被改变。

方式一:同步代码块:

  • synchronized(同步监视器){
  • //需要被同步的代码
    
  • }
  • 说明:
  • 1.操作共享数据的代码,即为需要被同步的代码
  • 2.共享数据:多个线程共同操作的变量,比如:ticket就是共享数据
  • 3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。
    要求:多个线程必须共用同一把锁
    补充:在实现Runnable接口创建多线程的方法中,我们可以考虑使用this充当同步监视器

方式二:同步方法

  • 5.同步方式,解决了线程的安全问题。—>好处
    操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。—>效率低

方式三:Lock锁

  • 解决线程安全问题的方式三:Lock锁 —JDK5.0新增
  • 1.面试题:synchronized与lock的异同?
  • 相同:都是去解决线程安全问题
  • 不同点:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
    Lock需要手动的启动同步(lock()),同时手动结束同步(unlock())
  • 2.优先使用顺序: lock ->同步代码块 ->同步方法
  • 面试题:如何解决线程的安全问题?有几种方式?
    三种:lock和两种synchronized

同步代码块的方法举例

①实现Runnable接口

//例子:创建三个窗口卖票,总票数为100张
//实现Runnable接口
class Window1 implements Runnable{
    private int ticket = 100;//不需要加static,因为只生成一个Window1的对象
    Object obj = new Object();
    @Override
    public void run() {
        while(true) {
            synchronized (obj) {//或者synchronized(this)
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}
public class WindowTest1 {
    public static void main(String[] args) {
        Window1 w1 =new Window1();
        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);
        t1.setName("窗口一:");
        t2.setName("窗口二:");
        t3.setName("窗口三:");
        t1.start();
        t2.start();
        t3.start();
    }

}


②继承Thread

/*
例子:创建三个窗口卖票,总票数为100张
说明:再继承Thread类创建多线程的方式中,慎用this充当同步监视器
      考虑使用当前类充当同比监视器
 */

public class WindowTest2 {
    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();
    }

}
class Window extends Thread{
    private  static int ticket = 100;//为什么写成静态,因为三个对象去共享100张票
    static Object obj = new Object();
    @Override
    public void run() {
        while(true) {
            //正确的
            synchronized(obj){
            //或者synchronized(Window.class){//class clazz = Window.class只会加载一次
            //错误的
             //   synchronized(this) 因为创建了三个对象,this指代不明
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName()+":"+ticket);
                ticket--;
            } else {
                break;
            }
        }
        }
    }
}

同步方法举例

①实现Runnable接口

/**
 * 使用同步方法实现Runnable接口的线程安全问题.
 *
 * 关于同步方法的总结:
 * 1.同步方法任然涉及到监视器,只是不需要显式的申明private synchronized void show()
 * 2.非静态的同步方法:同步监视器:this
 *   静态的同步方法:同步监视器:当前类本身
 */

class Window3 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while(true){
            show();
        }
    }
    private synchronized void show(){//同步监视器:this
        //synchronized (this){

        if (ticket > 0) {

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);

            ticket--;
        }
        //}
    }
}
public class WindowTest3 {
    public static void main(String[] args) {
        Window3 w = new Window3();

        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();
    }

}

②继承Thread

/*
例子:创建三个窗口卖票,总票数为100张
说明:再继承Thread类创建多线程的方式中,慎用this充当同步监视器
      考虑使用当前类充当同比监视器
 */

public class WindowTest4 {
    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();
    }

}
class Window4 extends Thread{
    private  static int ticket = 100;//为什么写成静态,因为三个对象去共享100张票
    @Override
    public void run() {
        while(true) {
             show();
            }
        }



    public static synchronized void show() {//同步监视器为当前类:window4.class
        //错误的 public symchronized voidshow()//同步监视器为t1,t2,t3,此种解决方式是错误的
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ticket);
            ticket--;
        }
    }
}

lock锁举例

class Window implements Runnable{
    private int ticket = 100;
    //1.实例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock(false);//默认值为false,true的意思为公平,谁先到谁先有使用权
    @Override
    public void run() {

        while(true) {
            //2.调用lock()
            lock.lock();
                try {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (ticket > 0) {
                        System.out.println(Thread.currentThread().getName() + "\t" + ticket);
                        ticket--;
                    }
                }finally {
                    //3.调用解锁方法:unlock()
                    lock.unlock();
                }


        }

    }
}

public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();

        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();
    }
}

八:线程的通信

  • 线程通信的例子:使用两个线程打印1-100,线程1,线程2交替打印
  • 涉及到的三个方法:
  • wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器。
  • notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的那个。
  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
  • 说明:
  • 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
  • 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalMonitorStateException异常。
  • 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。

面试题:sleep() 和 wait()的异同?

  • 相同点:一旦执行方法,都可以使得当前线程进入阻塞状态
  • 不同点:
    1)两个方法声明的位置不同,Thread类声明sleep(),Object类中声明wait()。
    2)调用的要求不同:sleep()可以在任何需要的场景下调用,wait()必须声明在同步代码块和同步方法中。
    3)关于是否是否同步监视器:如果两个方法都声明在同步代码块和同比监视器中,则sleep()不会释放锁,wait()会。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值